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


14

当通过echo传递时,上述命令的输出为:

# echo systemctl\ {restart,status}\ sshd\;
systemctl restart sshd; systemctl status sshd;

即使我将输出粘贴到终端,该命令仍然有效。但是当我尝试直接运行命令时,我得到:

# systemctl\ {restart,status}\ sshd\;
bash: systemctl restart sshd;: command not found...

我有两个问题。

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

Answers:


26

这是在外壳中完成的Brace扩展形式。大括号扩展的想法是正确的,但此处的用法不正确。当您打算这样做时:

systemctl\ {restart,status}\ sshd\;

该shell解释systemctl restart sshd;为一个长命令并尝试运行它,但找不到二进制文件以这种方式运行它。因为在此阶段,shell尝试在使用参数构建完整命令之前尝试对命令行中的项目进行标记化-但尚未发生。

对于这样的已知扩展值,您可以使用eval并且仍然很安全,但是请确保要尝试使用它进行扩展。

eval systemctl\ {restart,status}\ sshd\;

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

for action in restart status; do
    systemctl "$action" sshd
done

19

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

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

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

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

您想做的是影响(3)中的(2)。基于拆分的;阶段是在分析复合命令时处于阶段(2)。在大括号扩展发生时(3),尝试创建复合命令已经为时已晚。


6

第一行

echo systemctl\ {restart,status}\ sshd\;

扩展为3个令牌

  • 回声
  • systemctl重新启动sshd;
  • systemctl status sshd;

然后echo回声最后两个标记,看起来不错。

同样第二行

systemctl\ {restart,status}\ sshd\;

扩展为2个令牌

  • systemctl重新启动sshd;
  • systemctl status sshd;

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

您可能想eval systemctl\ {restart,status}\ sshd\;提防意外,从黑暗的一面开始您的旅程。


因此,解决方案是分词,对吗?如何才能做到这一点?
Somenath Sinha
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.