cmd 嵌套在从 sudo 处理的反引号中?

cmd 嵌套在从 sudo 处理的反引号中?

是否`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 有不同的语法。例如,fishhas(...)rc/ eshave`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)"

首先,它不会运行cmd2root,而且输出cmd2(这次,不会受到 split+glob 的影响,因为它在引号内)将被解释为sh代码,因此通常会构成命令注入漏洞。例如,如果cmd2输出$(reboot)sh则调用者sudo将被要求解释cmd1 $(reboot)并重新启动。

同样,如果您想传递变量的内容,sudo sh -c 'cmd1 $(cmd2) '"$var"请不要这样做sudo sh -c 'cmd1 $(cmd2 '"$var"')'你的shell(而不是由 启动的 shell sudo)到cmd1cmd2。相反,将这些变量的内容作为额外的内容传递论点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"
'

相关内容