为什么shell命令没有像我期望的那样按顺序执行?

时间:2014-08-31 01:31:35

标签: bash shell ubuntu

我编写了3个名为s1.sh s2.sh s3.sh的shell脚本。它们具有相同的内容:

#!/bin/ksh
echo $0 $$

和s.sh按顺序调用它们:

#!/bin/sh
echo $0 $$
exec ./s1.sh &
exec ./s2.sh &
exec ./s3.sh &

但结果是无序的:

victor@ThinkPad-Edge:~$ ./s.sh
./s.sh 3524
victor@ThinkPad-Edge:~$ ./s1.sh 3525
./s3.sh 3527
./s2.sh 3526

为什么不是s1 s2然后顺序s3?

如果我删除&在s.sh中:

#!/bin/sh
echo $0 $$
exec ./s1.sh 
exec ./s2.sh 
exec ./s3.sh 

输出:

$ ./s.sh
./s.sh 4022
./s1.sh 4022

缺少s2和s3,为什么?

4 个答案:

答案 0 :(得分:4)

他们一直按顺序执行(至少按顺序开始 - 注意id正在递增)。您为3个单独的程序打开3个单独的线程。一个(出于某种原因)比另一个快。如果您想按顺序使用它们,请从exec中取出&exec ./s1.sh &

答案 1 :(得分:2)

进程调度程序通过一次运行每个任务的片段,然后快速切换到另一个任务来实现明显的多任务处理。根据系统负载,I / O等待,优先级,调度算法等,几乎同时启动的两个进程可能会获得可用CPU的完全不同的分配。因此,无法保证您的三个进程中的哪一个首先到达echo语句。

这是非常基本的Unix知识;也许你应该读一本书或在线教程,如果你的意思是认真使用Unix。

如果您需要并行进程以特定顺序执行,请使用锁定机制(信号量,共享内存等)来防止执行代码的特定部分(称为“临界区”),然后再执行另一个。 (但是在shell脚本中这并不容易。如果你不想一直到C,请切换到Python或Perl。如果你可以忍受I / O延迟,可以使用锁文件。)

在第二个示例中,exec命令当前进程替换为另一个。因此,s1完全接管,并且shell永远不会看到启动s2s3的命令。

(这在你的第一个例子中并不明显,因为&导致shell首先分叉后台进程,基本上使exec无用。{/ p>

答案 2 :(得分:1)

&运算符将每个exec放在后台。实际上,您并行运行所有3个脚本。它们不会保持有序,因为操作系统只要有机会就会执行一些脚本,但它也会执行一堆其他的东西。一个过程可以比其他过程有更多的时间运行,从而使其更快完成。

答案 3 :(得分:0)

  

缺少s2和s3,为什么?

您不会错过s2s3 - s2s3正在替换或子shell中执行(当s.sh退出时(或被替换) ),它们失去与控制台的通信,导致它们的输出覆盖TTY上的先前输出。

其他答案已经讨论过,s1,s2,s3全部在替换shell exec)或子shell (不包含exec内执行以及如何删除exec&将强制执行s1,s2,s3。有两种情况需要讨论。一个exec存在而另一个不存在的地方。如果存在exec,则当前shell将被执行的进程替换(如注释中所指出的,父shell被终止)。

如果未使用exec,则在子shell中执行s1,s2,s3。您没有看到s2s3的输出,因为s.sh已在s2之前完成和/或退出,s3执行删除与控制台的通信(如果你看起来你会看到你显示一个额外的提示,然后是剩余的s(2,3).sh命令的输出。但是,有一种方法可以在s.sh退出之前完成它们。使用{{1} }。wait告诉wait在完成所有子进程s.sh之前不要退出。这提供了一个到控制台的输出路径。例如:

s1, s2, and s3

<强>输出:

#!/bin/bash

echo $0 $$
exec ./1.sh  &
exec ./s2.sh  &
exec ./s3.sh  &

wait