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

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

上述命令通过 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. 我在这里做错了什么?为什么不起作用?

答案1

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

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

答案2

这就是所谓的大括号扩展(如标签所示)。

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

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

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

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

答案3

第一行

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

扩展为 3 个令牌

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

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

同样第二行

systemctl\ {restart,status}\ sshd\;

扩展为 2 个代币

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

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

您可能希望从黑暗面开始您的旅程,并eval systemctl\ {restart,status}\ sshd\;提防意外情况。

相关内容