是否`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,它只是伪代码)。或者它依赖于外壳?
答案1
`...`
和$(...)
是相同的东西,但语法不同,一个来自 Bourne shell,另一个来自 Korn shell,前者已被弃用,但仍受类 Bourne shell 的支持,以向后兼容古老的 Bourne shell。
其他 shell 有不同的语法。例如,fish
has(...)
和rc
/ es
have`cmd
或`{more complex cmd}
, or`(sep){cmd}
指定不同的拆分行为。ksh93
并且mksh
还有${ ...; }
(无子壳)变体。
无论如何,这是 shell 语言中的语法,因此您需要一个 shell 来解释它并执行命令替换。
在:
sudo cmd1 `cmd2`
在类似 Bourne 的 shell 中,shell
- 在子进程中运行
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 的 shell 中,命令替换仍然在双引号内执行,因此不是做:
sudo sh -c "cmd1 $(cmd2)"
首先,它不会运行cmd2
为root
,而且输出cmd2
(这次,不会受到 split+glob 的影响,因为它在引号内)将被解释为sh
代码,因此通常会构成命令注入漏洞。例如,如果cmd2
输出$(reboot)
,sh
则调用者sudo
将被要求解释cmd1 $(reboot)
并重新启动。
同样,如果您想传递变量的内容,请不要这样做sudo sh -c 'cmd1 $(cmd2) '"$var"
你的shell(而不是由 启动的 shell sudo sh -c 'cmd1 $(cmd2 '"$var"')'
sudo
)到cmd1
或cmd2
。相反,将这些变量的内容作为额外的内容传递论点到sh
(不在代码sudo
参数),或通过环境变量(因此它们也成为启动的 shell 的变量):
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)
ifcmd2
输出$IFS
分隔列表时不带引号即可通配符模式。如果您希望cmd2
(不带尾随换行符)的输出作为整体传递一的参数cmd1
,您希望cmd1 "$(cmd2)"
或更可能cmd1 -- "$(cmd2)"
确保该参数不被视为选项(假设cmd1
支持该--
选项结束标记)。
因此,对于您的特定用例,这将是:
sudo DEVICE="$device" sh -c 'mount -- "$(blkid -u -- "$DEVICE")"'
mount
或者仅在成功时调用blkid
:
sudo DEVICE="$device" sh -c '
output=$(blkid -u -- "$DEVICE") &&
mount -- "$output"
'