Ubuntu 16.04.3では、非常に単純なbashスクリプトがあります。
test.sh
[[ 0 == 0 ]] && result="true" || result="false"
echo $result
echo $USER $Shell $0
非rootユーザーme
またはroot
として呼び出すと、期待どおりに機能します。 Sudo ./test.sh
を使用すると、構文エラーが表示されます。
$ ./test.sh
true
me /bin/bash ./test.sh
$ Sudo su
# ./test.sh
true
root /bin/bash ./test.sh
# exit
$ Sudo ./test.sh
./test.sh: 1: ./test.sh: [[: not found
false
root /bin/bash ./test.sh
これは何が原因ですか? me
が通常とSudo
の両方でこのスクリプトを使用できるように修正するにはどうすればよいですか?
すべてのスクリプトは Shebang で始まります。これがないと、スクリプトを開始するシェルは、どのインタープリターがスクリプトを実行すべきかを認識しません。1 そして、おそらくSudo ./script.sh
の場合のように、sh
で実行します。これはUbuntu 16.04ではdash
にリンクされています。 条件式[[
は bash
複合コマンド であるため、dash
はその処理方法を認識せず、エラーをスローしますあなたが遭遇しました。
ここでの解決策は、追加することです
#!/bin/bash
スクリプトの最初の行として。 Sudo bash ./script.sh
を使用して明示的に呼び出すと同じ結果になる場合がありますが、Shebangを使用する方法があります。
スクリプトを実行するシェルを確認するには、echo $0
を追加します。それは、echo $Shell
と同じではなく、 wiki.archlinux.org を引用して:
シェルには、ユーザーの優先シェルへのパスが含まれます。 Bashは起動時にこの変数を設定しますが、これは必ずしも現在実行中のシェルではないことに注意してください。
1:./test.sh
をbash
で開始したとき、それはbash
を想定しただけで、Sudo su
サブシェルについても同じことが言えます。
@ dessertの説明 のように、ここでの問題は、スクリプトに Shebang行 がないことです。 Shebangがない場合、Sudo
はデフォルトで/bin/sh
を使用してファイルを実行しようとします。どこにも文書化されていませんでしたが、Sudo
ソースコードを確認することで確認しました。ソースコードでは、ファイルpathnames.h
で次を見つけました。
#ifndef _PATH_BSHELL
#define _PATH_BSHELL "/bin/sh"
#endif /* _PATH_BSHELL */
これは、「変数_PATH_BSHELL
が定義されていない場合に設定し、/bin/sh
に設定する」ことを意味します。次に、ソースtarballに含まれるconfigure
スクリプトに、次のものがあります。
for p in "/bin/bash" "/usr/bin/sh" "/sbin/sh" "/usr/sbin/sh" "/bin/ksh" "/usr/bin/ksh" "/bin/bash" "/usr/bin/bash"; do
if test -f "$p"; then
found=yes
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $p" >&5
$as_echo "$p" >&6; }
cat >>confdefs.h <<EOF
#define _PATH_BSHELL "$p"
EOF
break
fi
done
このループは、/bin/bash
、/usr/bin/sh
、/sbin/sh
、/usr/sbin/sh
、または/bin/ksh
を探し、_PATH_BSHELL
をどちらか最初に見つかった。 /bin/sh
はリストの最初であり、存在するため、_PATH_BSHELL
は/bin/sh
に設定されます。これらすべての結果は、特に定義されていない限り、Sudo
のデフォルトシェルは/bin/sh
です。
したがって、Sudo
はデフォルトで/bin/sh
を使用して実行され、Ubuntuではdash
へのシンボリックリンクであり、POSIX準拠の最小シェルです。
$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Feb 27 2015 /bin/sh -> dash
[[
コンストラクトはbash機能であり、POSIX標準では定義されておらず、dash
で認識されません。
$ bash -c '[[ true ]] && echo yes'
yes
$ dash -c '[[ true ]] && echo yes'
dash: 1: [[: not found
詳細には、あなたが試した3つの呼び出しで:
./test.sh
いいえSudo
; Shebang行がない場合、シェルはファイル自体を実行しようとします。 bash
を実行しているため、これはbash ./test.sh
を効果的に実行して動作します。
Sudo su
の後に./test.sh
が続きます。
ここでは、ユーザーroot
の新しいシェルを開始しています。これは、そのユーザーの$Shell
環境変数で定義されているシェルであり、Ubuntuでは、ルートのデフォルトシェルはbash
です。
$ grep root /etc/passwd
root:x:0:0:root:/root:/bin/bash
Sudo ./test.sh
ここでは、Sudo
にコマンドを直接実行させています。デフォルトのシェルは上記のように/bin/sh
であるため、これにより/bin/sh
でスクリプトが実行されます。これはdash
であり、dash
は[[
。
注:Sudo
がデフォルトのシェルを設定する方法の詳細は、もう少し複雑に見えます。回答に記載されているファイルを/bin/bash
を指すように変更しようとしましたが、Sudo
は依然として/bin/sh
にデフォルト設定されていました。そのため、ソースコードには、デフォルトのシェルが定義されている他の場所が必要です。それにもかかわらず、主要な点(Sudo
がデフォルトでsh
に設定されていること)は依然として有効です。