为什么 systemctl\ {restart,status}\ sshd\; 工作?

Som*_*nha 14 command-line bash brace-expansion

通过 echo 时上述命令的输出是:

# echo systemctl\ {restart,status}\ sshd\;
systemctl restart sshd; systemctl status sshd;
Run Code Online (Sandbox Code Playgroud)

即使我将输出粘贴到终端,该命令也能工作。但是当我尝试直接运行命令时,我得到:

# systemctl\ {restart,status}\ sshd\;
bash: systemctl restart sshd;: command not found...
Run Code Online (Sandbox Code Playgroud)

我有两个问题..

  1. 这种替换和扩展的方法到底叫什么?(以便我可以研究它并了解有关它的更多信息以及如何正确使用它)。
  2. 我在这里做错了什么?为什么不起作用?

Ini*_*ian 26

它是在 shell 中完成的Brace 扩展的一种形式。大括号扩展的想法是正确的,但它的使用方式在这里是不正确的。当您打算这样做时:

systemctl\ {restart,status}\ sshd\;
Run Code Online (Sandbox Code Playgroud)

shell 将解释systemctl restart sshd;为一个长命令并尝试运行它,但它找不到二进制文件来运行它。因为在这个阶段,shell 会在构建带有参数的完整命令之前尝试对命令行中的项目进行标记——但这还没有发生。

对于这些已知的扩展值,您可以使用eval并且仍然是安全的,但请确保您尝试用它扩展什么。

eval systemctl\ {restart,status}\ sshd\;
Run Code Online (Sandbox Code Playgroud)

但我宁愿使用循环而不是 with for,而不是尝试编写单行或使用eval

for action in restart status; do
    systemctl "$action" sshd
done
Run Code Online (Sandbox Code Playgroud)


mur*_*uru 19

这称为大括号扩展(如标记所示)。

我在这里做错了什么?为什么不起作用?

考虑在 bash 中读取和执行命令行所涉及的阶段(例如):

  1. 读一行
  2. 将可能的复合命令解析为组件简单命令
  3. 对简单命令进行各种扩展(大括号扩展、分词、通配等)
  4. 然后执行简单的命令(为清楚起见省略了其他阶段)。

你想要做的是从(3)影响(2)。;当它解析复合命令时,基于的拆分处于阶段 (2)。当 (3) 发生大括号扩展时,尝试创建复合命令已经太晚了。


Arc*_*mar 6

第一行

echo systemctl\ {restart,status}\ sshd\;
Run Code Online (Sandbox Code Playgroud)

扩展为 3 个令牌

  • 回声
  • systemctl 重启 sshd;
  • systemctl 状态 sshd;

然后echo echo 最后两个token,看起来没问题。

同样的第二行

systemctl\ {restart,status}\ sshd\;
Run Code Online (Sandbox Code Playgroud)

扩展为 2 个令牌

  • systemctl 重启 sshd;
  • systemctl 状态 sshd;

和 bash 尝试寻找systemctl restart sshd;它找不到的可执行文件。

您可能希望通过eval systemctl\ {restart,status}\ sshd\;提防意外开始您的黑暗面之旅。