bash:在后台启动多个链接命令

bash:在后台启动多个链接命令,bash,background,command,Bash,Background,Command,我试图在后台使用bash并行运行一些命令。以下是我想做的: forloop { //this part is actually written in perl //call command sequence print `touch .file1.lock; cp bigfile1 /destination; rm .file1.lock;`; } 反勾号(``)之间的部分生成一个新的shell并连续执行命令。问题是,只有在执行最后一个命令后,对原始程序的控制才会返回。我希望在后台

我试图在后台使用bash并行运行一些命令。以下是我想做的:

forloop {
  //this part is actually written in perl
  //call command sequence
  print `touch .file1.lock; cp bigfile1 /destination; rm .file1.lock;`;
}
反勾号(``)之间的部分生成一个新的shell并连续执行命令。问题是,只有在执行最后一个命令后,对原始程序的控制才会返回。我希望在后台执行整个语句(我不希望有任何输出/返回值),并且希望循环继续运行

在所有生成的shell完成之前,调用程序(具有循环的程序)不会结束

我可以在perl中使用线程来生成调用不同shell的不同线程,但这似乎是一种过度杀伤力

我可以启动一个shell,给它一组命令并告诉它转到后台吗

for command in $commands
do
    "$command" &
done
wait

命令末尾的符号在后台运行,而
wait
则等待后台任务完成。

尝试将命令放在带&s的大括号中,如下所示:

{command1 & ; command2 & ; command3 & ; }
print `touch .file1.lock && cp bigfile1 /destination && rm .file1.lock &`;
这不会创建子shell,而是在后台执行一组命令


HTH

我还没有测试过这个,但是怎么样

print `(touch .file1.lock; cp bigfile1 /destination; rm .file1.lock;) &`;

括号中的意思是在子shell中执行,但这不应该造成伤害。

谢谢Hugh,成功了:

adrianp@frost:~$ (echo "started"; sleep 15; echo "stopped")
started
stopped
adrianp@frost:~$ (echo "started"; sleep 15; echo "stopped") &
started
[1] 7101
adrianp@frost:~$ stopped

[1]+  Done                    ( echo "started"; sleep 15; echo "stopped" )
adrianp@frost:~$ 
其他想法不起作用,因为它们在后台启动每个命令,而不是命令序列(这在我的例子中很重要!)


再次感谢你

我不知道为什么没有人给出正确的答案:

my @children;
for (...) {
    ...
    my $child = fork;
    exec "touch .file1.lock; cp bigfile1 /destination; rm .file1.lock;" if $child == 0;
    push @children, $child;
}
# and if you want to wait for them to finish,
waitpid($_) for @children;
这将导致Perl生成子命令来运行每个命令,并允许您等待所有子命令完成后再继续

顺便说一下

print `some command`

将相同的内容输出到stdout,但是第一个有更高的开销,因为Perl必须捕获所有的“
某些命令的输出”(对于bash,IMO),但是正如Mad_Ady指出的,它不会处理“锁”文件。这应:

如果还有其他待处理的作业,等待也将等待这些作业。如果只需要等待副本,则可以累积这些PID并只等待这些PID。如果没有,您可以删除带有“pids”的3行,但它更一般

此外,我还添加了检查以避免复制:

pids=
for file in bigfile*
do
    # Skip if file is not newer...
    targ=/destination/$(basename "${file}")
    [ "$targ" -nt "$file" ] && continue

    # Use a lock file:  ".fileN.lock" for each "bigfileN"
    lock=".${file##*/big}.lock"
    ( touch $lock; cp "$file" "$targ"; rm $lock ) &
    pids="$pids $!"
done
wait $pids

顺便说一句,看起来您正在将新文件复制到FTP存储库(或类似存储库)。如果是这样,您可以考虑复制/重命名策略,而不是锁定文件(但这是另一个主题)。

使用AT作业运行命令:

# date
# jue sep 13 12:43:21 CEST 2012
# at 12:45
warning: commands will be executed using /bin/sh
at> command1
at> command2
at> ...
at> CTRL-d
at> <EOT>
job 20 at Thu Sep 13 12:45:00 2012
#日期
#jue sep 13 12:43:21 CEST 2012
#12点45分
警告:将使用/bin/sh执行命令
at>command1
at>command2
在>。。。
at>CTRL-d
在>
2012年9月13日星期四12:45:00第20次工作

结果将通过邮件发送到您的帐户。

您正在寻找的bash工具称为
复合命令。有关更多信息,请参见手册页:

复合命令 复合命令是以下命令之一:

   (list) list  is  executed  in a subshell environment (see COMMAND EXECUTION ENVIRONMENT below).  Variable assignments and
          builtin commands that affect the shell's environment do not remain in effect after  the  command  completes.   The
          return status is the exit status of list.

   { list; }
          list  is  simply  executed in the current shell environment.  list must be terminated with a newline or semicolon.
          This is known as a group command.  The return status is the exit status of list.  Note that unlike the metacharac‐
          ters  (  and  ),  {  and  } are reserved words and must occur where a reserved word is permitted to be recognized.
          Since they do not cause a word break, they must be separated from list by whitespace or another shell  metacharac‐
          ter.
还有其他类型,但这可能是最常见的两种类型。第一个是parens,它将在子shell中运行一系列命令,而第二个是花括号,它将在当前shell中运行一系列命令

帕伦斯 大括号
另一种方法是使用以下语法:

{ command1; command2; command3; } &
wait
请注意,
&
位于命令组的末尾,而不是每个命令之后。最后一个命令后面的分号是必需的,第一个括号后面和最后一个括号之前的空格也是必需的。末尾的
wait
确保在生成的子进程(命令组)结束之前不会杀死父进程

您还可以做一些奇特的事情,比如重定向
stderr
stdout

{ command1; command2; command3; } 2>&2 1>&1 &
您的示例如下所示:

forloop() {
    { touch .file1.lock; cp bigfile1 /destination; rm .file1.lock; } &
}
# ... do some other concurrent stuff
wait # wait for childs to end

我在这里偶然发现了这个线程,并决定编写一个代码片段来生成链接语句作为后台作业。我在BASH for Linux、KSH for ibmaix和Busybox的ASH for Android上进行了测试,所以我认为可以肯定地说,它可以在任何类似Bourne的shell上工作

processes=0;
for X in `seq 0 10`; do
   let processes+=1;
   { { echo Job $processes; sleep 3; echo End of job $processes; } & };
   if [[ $processes -eq 5 ]]; then
      wait;
      processes=0;
   fi;
done;

此代码运行大量后台作业,但并发作业的数量不超过一定的限制。例如,您可以使用它使用
xz
重新压缩大量gzip文件,而不需要大量
xz
进程占用您的全部内存并使您的计算机崩溃:在这种情况下,您使用
*
作为
的列表,批处理作业将是
gzip-cd“$X”| xz-9c>“${X%.gz}.xz”

如果有人仍然感兴趣,您可以不调用如下子shell:

{command1 & ; command2 & ; command3 & ; }
print `touch .file1.lock && cp bigfile1 /destination && rm .file1.lock &`;
在for循环中分叉:

用于x中的i;do((a;b;c;)&);完成

例如:


用于500 300 100中的i;do((printf“Start$i:”;date;dd if=/dev/zero of=testfile_$i bs=1m count=$i2>/dev/null;printf“End$i:”;date;)&&sleep 1;完成

您可以使用GNU
parallel
命令并行运行作业。速度越快越安全

我猜您正在尝试将多个大文件从源复制到目标。为此,你可以和下面的陈述同时进行

$ ls *|parallel -kj0 --eta 'cp {} /tmp/destination'
由于我们使用了
-j0
选项,所有文件都将并行复制。如果需要减少并行进程的数量,则可以使用
-j
,其中
是要执行的并行进程的数量

Parallel还将收集流程的输出,并按顺序(使用
-k
选项)报告它,这是其他作业控制机制无法做到的


--eta
选项将为您提供正在进行的流程的详细统计信息。因此,我们可以知道该过程可能是如何完成的,需要多长时间才能完成。

在子shell中运行命令:

(command1 ; command2 ; command3) &

您可以将参数传递给命令组(具有顺序命令)并在后台运行它们

for hrNum in {00..11};
do
    oneHour=$((10#$hrNum + 0))
    secondHour=$((10#$hrNum + 12))
    { echo "$oneHour"; echo "$secondHour"; } &
    wait
done

但是它们将并行执行,这不是OP想要的
for hrNum in {00..11};
do
    oneHour=$((10#$hrNum + 0))
    secondHour=$((10#$hrNum + 12))
    { echo "$oneHour"; echo "$secondHour"; } &
    wait
done