「sudo --login」で「sh -c」を実行すると、位置パラメータは拡張されません。解決策はありますか?

「sudo --login」で「sh -c」を実行すると、位置パラメータは拡張されません。解決策はありますか?

私は次の場所パラメータを使用する「インラインスクリプト」を作成しました。

$ sudo sh -c 'echo "p0=$0" && echo "p1=$1" && echo "p2=$2" && echo "all=$@"' sh 1 2
p0=sh
p1=1
p2=2
all=1 2

実際にrun my script inlineを使いたいですsudo --login。ただし、位置パラメータは何の影響もありません。動作させる方法はありますか?

(この動作が文書化されているのか、どこかに標準化されているのかもしれません。)

$ sudo --login sh -c 'echo "p0=$0" && echo "p1=$1" && echo "p2=$2" && echo "all=$@"' sh 1 2
p0=-bash
p1=
p2=
all=1 2

ソフトウェアバージョン:

$ sh --version
GNU bash, version 5.0.7(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

$ sudo --version
Sudo version 1.8.27
Sudoers policy plugin version 1.8.27
Sudoers file grammar version 46
Sudoers I/O plugin version 1.8.27

ベストアンサー1

同じ理由で

sudo --login echo '$HOME'

を出力する代わりに、$HOME変数$HOME(対象ユーザーが指定したsudo)の内容を出力します。

あなたの場合はそうではありません。sh -cは位置パラメータを拡張しません。しかし、起動時に(ログインシェルを介して)拡張されたため$0です。$1$2sh

ここでもっと驚くべきことは、あなたがそれを見る理由ですall=1 2$@sudo --login echo '$@'

-s/--shellおよび-i/--login実行シェルはすべてコマンドを実行します。しかし、sudoとても奇妙な方法です。

sudo -s 'some shell code'説明するためにシェルを実行したかったのですが、some shell codeそれは目的ではありません。これを行うには-s、まだ単純なコマンドを実行し、\シェルがこれを実行することを希望していくつかの文字を引用しようとします。

sudo -s 'echo test'しかし、これをしてはいけませんsudo -s echo test。最初のケースでは、sudoは実際にecho\ testシェルコードに渡されます。 Bourneに似たシェルは、名前付きコマンドを実行しようとします'echo test'。シェルを使用すると、引数を引数として使用してコマンドをrc実行します。echo\test

SPCに加えて、いくつかのsudoエスケープ文字があります。これには、目に見えない数字、、、、、、、、、、、、、、が含まれますが、;奇妙なことではありません(またはこれがこれらの/オプションの唯一の理由かもしれません:シェル拡張変数を許可します)。|()*&=\$-s--login

しかし@。見たらパスワード、ASCII演算を除くすべてのバイトをエスケープし_ます。-$

 if (!isalnum((unsigned char)*src) && *src != '_' && *src != '-' && *src != '$')
   *dst++ = '\\';

だから:

sudo -s echo '$@'

sudo実際に実行されます"$SHELL" -c 'echo $\@'。これは、あなたの例で$@始まったシェルが拡張されるのではなく、sudo --login 実行するように指示するシェルである理由を説明します。

あなたの

sudo sh -c 'echo "p0=$0" && echo "p1=$1" && echo "p2=$2" && echo "all=$@"' sh 1 2

sudorootログインシェル(あなたの場合)を実行しbash、以下を解釈するように指示します。

sh -c echo\ \"p0\=$0\"\ \&\&\ echo\ \"p1\=$1\"\ \&\&\ echo\ \"p2\=$2\"\ \&\&\ echo\ \"all\=$\@\" sh 1 2

パラメータはスペースとすべてのSPC、、、、、、文字に関連付けられますが、"エスケープされません。これはエスケープされないため、bashログインシェルはバックスラッシュのため拡張されません。=&@$$$0$1$2$\@

以下で見ることができます:

$ SHELL=echo sudo -s sh -c 'echo "p0=$0" && echo "p1=$1" && echo "p2=$2" && echo "all=$@"' sh 1 2
-c sh -c echo\ \"p0\=$0\"\ \&\&\ echo\ \"p1\=$1\"\ \&\&\ echo\ \"p2\=$2\"\ \&\&\ echo\ \"all\=$\@\" sh 1 2

このように、ログインbashシェルは最終的に最初のパラメータshとして実行されます。-c

echo "p0=-bash" && echo "p1=" && echo "p2=" && echo "all=$@"

2番目のパラメータとしてsh、3番目、4番目、5番目のパラメータ1として2

${0}この問題を解決するには、代わりに使用してください$0sudoこれは、$\{0\}ログインシェルがコンテンツに拡張するのを防ぐためです。それ $0:

$ sudo --login sh -c 'echo "p0=${0}" && echo "p1=${1}" && echo "p2=${2}" && echo "all=${@}"' sh 1 2
p0=sh
p1=1
p2=2
all=1 2

編集者:歴史はその理由を明らかにします。

コードを見てみると、より多くの発見が行われます。 Unescapabilityは$2013年に導入されたようです。今回の変更を通じて。おすすめバグ #564これは以下を指します。バグ #413

バグ#413があったようです。「安定的」sudo予想通りに行われた。

それは:

sudo -i 'some shell code'

ログインシェルにシェルコードを解釈します(そしてシェルコードが解釈されるようにsudo -s 'some shell code'します)。$SHELLしかし、バグ#413の解決策は、バグを報告した人がバグがどのように機能するかを理解していなかったため、問題を解決しました。 bug#564は問題をさらに深化させます(bug#413の解決策によって引き起こされた損傷の一部のみを取り消そうとします)。

2009年からsudo1.7.1をコンパイルしましたが、-s/-iオプションは期待どおりに機能しました。1.7.3(バグ#413の解決策)は明らかに期待どおりに機能します。

$ sudo-1.7.1 -i 'echo "$SHELL"'
/bin/bash
$ sudo-1.7.3 -i 'echo "$SHELL"'
-bash: echo "$SHELL": command not found
$ sudo-1.8.21p2 -i 'echo "$SHELL"'
-bash: echo "/bin/bash": No such file or directory
$ sudo-1.7.3 -i sh -c 'echo "p0=$0" && echo "p1=$1" && echo "p2=$2" && echo "all=$@"' sh 1 2
p0=sh
p1=1
p2=2
all=1 2

\バグ#413の修正で導入されたエスケープは、すべてのバイト(文字ではなく)の前でを押すことはすべてのバイトに適用されないため、だまされやすいです。

rcwhereが引用演算子ではない明白な場合を除いて、\ほとんどのシェルは改行文字を引用できません\

$ SHELL=sh sudo -s echo $'a\nb'
ab
$ SHELL=csh  sudo -s echo $'a\nb'
a b

これはまた、空のパラメータが削除されることを意味します。

$ sudo printf '<%s>\n' a '' b
<a>
<>
<b>
$ sudo -s printf '<%s>\n' a '' b
<a>
<b>

\また、各項目の前に挿入してバイトは文字を文字セット内の他の文字に変換します。ここで、\バイト0x5c(のエンコード)は他の文字の中にあります。

$ SHELL=bash LC_ALL=zh_HK.big5hkscs sudo -s echo $'\xa3``uname`\xa3`'
bash: line 2: Linuxα: command not found
α

0xa3 0x60はこのロケールのギリシャ語イプシロンです。 sudo は 0x60s を 0x5c 0x60 に変更し、0xa3 0x5c はunameコマンドが実行される理由を説明するギリシャ文字です。sudo変更

ε`uname`ε

到着

\α`\`uname\`\α`

もちろん、、パラメータ、および(有効なPOSIX変数名がある場所)は拡張されますが、他のパラメータは拡張されていないため(たとえば、ここ$-でも、、、)または(//)または(//...)。$$$varnamevarname$@$!$?$*$#${varname}$var[1]cshtcshzsh$var(1)rces

おすすめ記事