Bash

cmd嵌套在從sudo處理的反引號中?

  • July 22, 2020

commands是否使用(不推薦使用的)反引號以 root 權限(sudo從命令行)執行嵌套,而命令替換$(...)不是?

例如

sudo mount `blkid -u /dev/sda1` ...
sudo mount `sudo blkid -u /dev/sda1` ...

對比

sudo mount $(blkid -u /dev/sda1) ...
sudo mount $(sudo blkid -u /dev/sda1) ...

方法之間有區別嗎?我什至不太確定這四行中哪一行是正確的用法(關於sudo,而不是 blkid,它只是虛擬碼)。還是它依賴於外殼?

...並且$(...)是具有不同語法的相同事物,一個 if 來自 Bourne shell,另一個來自 Korn shell,前者已被棄用,但仍被 Bourne-like shell 支持,以便與古老的 Bourne shell 向後兼容。

其他 shell 對此有不同的語法。例如,fishhas(...)rc/ eshave cmd`or {more complex cmd},或``(sep){cmd}指定不同的拆分行為。ksh93並且mksh還有${ ...; }(無子外殼)變體。

無論如何,這是 shell 語言中的語法,因此您需要一個 shell 來解釋它並執行命令替換。

在:

sudo cmd1 `cmd2`

在類伯恩貝殼中,貝殼

  • 在子程序中執行cmd2,其輸出重定向到管道
  • 從管道的另一端讀取該 cmd 的輸出,
  • 刪除尾隨的換行符,
  • 根據拆分結果$IFS
  • 對生成的單詞執行文件名生成(除了 in zsh;一些 ksh 變體也執行大括號擴展)
  • 然後將生成的單詞作為單獨的參數傳遞給sudo在另一個子程序中執行的命令。

sudo然後更改 uids 並執行它作為參數傳遞的命令。

如果你想cmd2使用不同的 uid 執行,你需要sudo執行一個 shell 來解釋執行命令替換的 shell 程式碼:

sudo sh -c 'cmd1 $(cmd2)'
sudo fish -c 'cmd1 (cmd2)'
sudo rc -c 'cmd1 `cmd2'

等等。

請注意,在 Bourne-like shell 中,命令替換仍然在雙引號內執行,所以要這樣做:

sudo sh -c "cmd1 $(cmd2)"

首先,它不會cmd2作為執行root,而且cmd2(這一次,因為它在引號內,所以不受 split+glob 的影響)的輸出將被解釋為sh程式碼,因此通常會構成命令注入漏洞。例如,如果cmd2輸出$(reboot)sh呼叫者sudo將被要求解釋cmd1 $(reboot)並重新啟動。

同樣,如果您想將shell 變數的內容(與以 開頭的變數相反)傳遞給sudo sh -c 'cmd1 $(cmd2) '"$var"or ,請不要這樣做。相反,將這些變數的內容作為額外參數傳遞給(不在程式碼參數內部),或通過環境變數(因此它們也成為 shell 的變數):sudo sh -c 'cmd1 $(cmd2 '"$var"')'``sudo``cmd1``cmd2``sh``sudo

sudo sh -c 'cmd1 $(cmd2) "$1"' sh "$var"
sudo VAR="$var" sh -c 'cmd1 $(cmd2) "$VAR"'

sudo sh -c 'cmd1 $(cmd2 "$1")' sh "$var"
sudo VAR="$var" sh -c 'cmd1 $(cmd2 "$VAR")'

在這裡,您還可以隨時執行以下操作:

sudo cmd1 $(sudo cmd2) "$var"
sudo cmd1 $(sudo cmd2 "$var")

那就是讓你的shell 通過兩個單獨的呼叫來執行這兩個命令,sudo因此它們都以提升的權限執行。

如上所述,在類似 Bourne 的 shell 中(但也適用於類似 csh 的 shell),不帶引號的命令替換受 split+glob 的影響,因此$(cmd2)如果cmd1 $(cmd2)輸出cmd2分隔$IFS列表萬用字元模式。如果您希望cmd2(不帶尾隨換行符)的輸出作為一個參數作為一個整體傳遞給cmd1,您希望cmd1 "$(cmd2)"或更可能cmd1 -- "$(cmd2)"確保該參數不被視為選項(假設cmd1支持--end-選項標記)。

因此,對於您的特定案例,這將是:

sudo DEVICE="$device" sh -c 'mount -- "$(blkid -u -- "$DEVICE")"'

mount僅在blkid成功時呼叫:

sudo DEVICE="$device" sh -c '
 output=$(blkid -u -- "$DEVICE") &&
   mount -- "$output"
'

引用自:https://unix.stackexchange.com/questions/599682