Contents

命令链接:内联或已运行的进程

1. 概述

有时我们需要在 Linux 中执行多个命令序列(命令链)以连接它们的结果以实现非常具体的任务。比如下载一个文件,解压,然后删除压缩后的文件。

在这个简短的教程中,我们将看到一些在 Linux 中使用*bash *序列化命令的方法。即使其中一些已经在运行。

2. 内联命令链接

bash语法为用户提供了极大的灵活性和强大的功能。我们可以制作很长的命令序列来执行最多样化的职责:

<command1> <arguments1> <chaining operator> <command2> <arguments2> ...

链式操作有几种,我们来看看最常用的:

  • ; (分号)——不管结果如何,右边的命令在左边的命令之后执行
  • & (&) – 左边的命令将在后台运行,右边的命令立即启动
  • | (pipe) – 左边命令的标准输出通过管道进入右边命令的标准输入
  • && (AND) – 如果左边的命令成功,则右边的命令执行(零返回码)
  • || (OR) – 如果左边的命令不成功,则右边的命令执行(非零返回码)*

也可以使用括号括起来的语句链来定义要在子 shell 中执行的块:

( <command1> && <command2> ) & ( <command3> && <command4> ) &

这将并行运行两个命令序列。在每一个中,第一个命令结果条件最后一个。

3. 与已运行进程的命令链接

让我们看看我们如何使用wait 程序在另一个已经运行的命令之后执行命令。该实用程序是同名系统调用的包装器。

它接收一个pids(进程标识号)列表作为其参数。因此,它会挂起 shell,直到所有进程都完成。如果没有参数被通知,将等待当前 shell 的所有后台进程。

如果我们不知道正在运行的进程的pid,**您可以使用pidof 命令检索所有正在运行的同名进程的pid。**例如,我们将启动三个后台 10 秒睡眠,然后等待它们:

$ sleep 10 &
[1] 26176
$ sleep 10 &
[2] 26178
$ sleep 10 &
[3] 26179
$ wait $(pidof sleep) && echo Waited for 3 10-second sleeps
[1]   Done                    sleep 10
[2]-  Done                    sleep 10
[3]+  Done                    sleep 10
Waited for 3 10-second sleeps

psgreptr  和cut 的帮助下,使用一些命令链接可以实现pidof的相同结果。只是为了踢球,它会像这样:

$ wait $(ps -ef | grep <process name> | tr -s ' ' | cut -f 2 -d ' ' ) && echo Waited for 3 10-second sleeps

上面显示的命令链是另一个很好的例子,说明我们如何链接命令以获得特定结果。构造*$()*意味着括号内的块的结果将用作 等待命令的参数。在这种情况下:

  • ps -ef – 收集所有进程的详细信息
  • grep process_name – 从ps -ef输出中选择包含process_name的行
  • tr -s ’ ‘ –从grep的输出中删除任何重复出现的 ’ ‘(空格)
  • cut -d ’ ’ -f 2 – 从 tr输出中选择第二个字段,使用 ’ ‘(空格)作为字段分隔符。在这种情况下, 在前面的步骤中列出和过滤的进程的pid

4. wait命令的局限性

至于wait返回代码,wait尝试返回它等待的最后一个命令的退出代码。然而,它确实不那么可靠,例如,如果我们使用一个已经完成的命令的pid,它不能返回它的实际结果。此外,如果返回代码大于 128,则无法知道应用程序是由于信号还是自行结束的

最后,wait的另一个限制是它只能等待在同一个 shell 会话上启动的应用程序。如果我们需要等待其他用户的进程或在其他bash会话中打开,我们将不得不使用其他不太直接的方式,如pidof循环:

while ( pidof -q <command_to_wait> ); do sleep 1; done && <command_to_execute_after>

此示例用作wait 的更通用且功能更弱的替代品。它取决于休眠时间,无法评估目标进程的返回码。请注意,在 shell 循环的迭代之间使用sleep 始终是将 CPU 周期正确返回给系统的好习惯,尤其是当使用的命令结束得太快时。