如果我從“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
我實際上想使用
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
出於同樣的原因
sudo --login echo '$HOME'
不輸出
$HOME
,而是$HOME
變數的內容(目標使用者的,由 設置sudo
)。在您的情況下,這不是因為sh -c 沒有擴展位置參數,而是因為
$0
,$1
,在啟動$2
時已經(通過登錄外殼)擴展了sh
。這裡更令人驚訝的是為什麼你會看到
all=1 2
.$@
這與您看到的原因相同sudo --login echo '$@'
。
-s
/--shell
和-i
/都--login
執行一個 shell 來執行命令。但sudo
它以一種非常奇怪的方式進行。我希望
sudo -s 'some shell code'
執行一個 shell 來解釋some shell code
,但這不是它的作用。使用-s
,它仍然希望執行一個簡單的命令,並嘗試引用(使用\
)一些字元,以希望通過該 shell 實現它。你不是故意的
sudo -s 'echo test'
,但是sudo -s echo test
。在第一種情況下,sudo 實際上是echo\ test
作為 shell 程式碼傳遞的。在類似 Bourne 的 shell 中,它會嘗試執行一個名為'echo test'
. 使用rc
shell,它將執行一個echo\
以test
作為參數呼叫的命令。除了 SPC 之外,還有一些字元會
sudo
轉義。這包括反引號,;
,|
,(
,)
,*
,&
,=
,\
但奇怪的是,不是(或者這可能是這些/選項$
中唯一存在的理由:讓 shell 擴展變數)。-s``--login
它確實包括
@
。如果您查看程式碼,它會轉義除 ASCII alnum、 和 之外的_
所有-
字節$
。if (!isalnum((unsigned char)*src) && *src != '_' && *src != '-' && *src != '$') *dst++ = '\\';
所以:
sudo -s echo '$@'
sudo
實際執行"$SHELL" -c 'echo $\@'
,這解釋了為什麼在您的範例中,$@
不是由啟動的 shellsudo --login
而是由您告訴它執行的 shell 擴展的。在你的
sudo sh -c 'echo "p0=$0" && echo "p1=$1" && echo "p2=$2" && echo "all=$@"' sh 1 2
sudo
執行root
的登錄外殼(bash
在您的情況下)並告訴它解釋:sh -c echo\ \"p0\=$0\"\ \&\&\ echo\ \"p1\=$1\"\ \&\&\ echo\ \"p2\=$2\"\ \&\&\ echo\ \"all\=$\@\" sh 1 2
參數已用空格和所有 SPC、
"
、=
、&
、@
字元連接,但沒有$
被轉義。因為那些$
沒有被轉義的 bash 登錄 shell 會擴展$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
shell最終sh
以-c
第一個參數執行,echo "p0=-bash" && echo "p1=" && echo "p2=" && echo "all=$@"
作為第二個參數,
sh
,1
,2
作為第 3、第 4 和第 5 個。要解決它,您可以使用
${0}
而不是$0
, 因為sudo
將其轉換為$\{0\}
可防止登錄 shell 將其擴展到其內容$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
編輯:歷史揭示了其背後的原因
查看程式碼時的更多發現。
$
顯然是在 2013 年通過這種變化引入了non-escaping 。其中指的是bug#564指的是bug#413。看起來在那個 bug#413 被*“fixed”*之前,
sudo
表現得和我預期的一樣。那是:
sudo -i 'some shell code'
讓登錄 shell 解釋該 shell 程式碼(並
sudo -s 'some shell code'
解釋$SHELL
該 shell 程式碼)。但是 bug#413 解決方案破壞了它,因為報告錯誤的人不理解它是這樣工作的。並且錯誤#564 進一步破壞了它(試圖僅恢復錯誤#413 解決方案引入的部分破壞)。我從 2009 年開始編譯
sudo
1.7.1 並且-s
/-i
選項按我預期的那樣工作。1.7.3
(具有 bug#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 時引入的轉義很容易被愚弄,因為
\
在所有字節(而不是字元)前面敲擊 a 並不適用於所有人。除了
rc
where\
甚至不是引用運算符的明顯情況之外,在大多數 shell 中,換行符不能用 引用\
:$ 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>
\
此外,通過在每個byte之前插入 a ,它將字元轉換為字元集中的其他字元,其中\
在其他字元中找到字節 0x5c (的編碼):$ SHELL=bash LC_ALL=zh_HK.big5hkscs sudo -s echo $'\xa3``uname`\xa3`' bash: line 2: Linuxα: command not found α
0xa3 0x60 是該語言環境中的希臘 Epsilon。sudo 將 0x60s 更改為 0x5c 0x60 和 0xa3 0x5c 是希臘字母,這就解釋了為什麼
uname
執行命令。sudo
改變了ε`uname`ε
到
\α`\`uname\`\α`
當然,行為最終令人驚訝,因為
$-
,$$
, 位置參數和$varname
(其中varname
是有效的 POSIX 變數名)被擴展,但其他參數(如$@
這裡,還有$!
,$?
,$*
,$#
)或${varname}
or$var[1]
(csh
/tcsh
/zsh
) 或$var(1)
(rc
/es
/…)。