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

我正在尝试使用bash在后台运行一些命令。 这是我想要做的:

forloop { //this part is actually written in perl //call command sequence print `touch .file1.lock; cp bigfile1 /destination; rm .file1.lock;`; } 

反引号(“)之间的部分产生一个新的shell并连续执行这些命令。 事情是,控制到原来的程序只有在最后一个命令执行后才返回。 我想在后台执行整个语句(我不期望任何输出/返回值),我希望循环继续运行。

调用程序(具有循环的程序)在所有产生的炮弹完成之前不会结束。

我可以在Perl中使用线程来产生不同的线程,调用不同的shell,但它似乎是一个矫枉过正的…

我可以启动一个shell,给它一套命令,并告诉它去背景?

我没有testing过,但是怎么样

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

括号意味着在一个子shell中执行,但不应该伤害。

谢谢休,那是这样做的:

 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:~$ 

其他想法不起作用,因为他们在后台启动每个命令,而不是命令序列(这对我来说很重要!)。

再次感谢你!

另一种方法是使用语法:

 { command1; command2; command3; } & wait 

没有&后命令,但在cmd组结束。 最后的wait确保产生的孩子将有父母直到结束。

你也可以做像redirectstderrstdout花哨的东西:

 { 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 
 for command in $commands do "$command" & done wait 

命令末尾的&符号在后台运行,等待,直到后台任务完成。

GavinCattell得到了最接近的(bash,IMO),但正如Mad_Ady指出的,它不会处理“locking”文件。 这应该:

如果还有其他工作正在等待, 等待也会等待。 如果您只需等待副本,则可以累积这些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存储库(或类似)。 如果是这样,你可以考虑一个复制/重命名策略,而不是locking文件(但这是另一个话题)。

你正在寻找的bash中的工具叫做Compound Commands 。 请参阅手册页获取更多信息:

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

  (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. 

还有其他的,但这些可能是最常见的两种types。 第一个,parens将在子shell中运行一系列命令,而第二个,大括号将在当前shell中串联一个命令列表。

括号

 % ( date; sleep 5; date; ) Sat Jan 26 06:52:46 EST 2013 Sat Jan 26 06:52:51 EST 2013 

大括号

 % { date; sleep 5; date; } Sat Jan 26 06:52:13 EST 2013 Sat Jan 26 06:52:18 EST 2013 

使用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 

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

我在这里偶然发现了这个线程,并决定放置一个代码片段来产生链式语句作为后台作业。 我在BASH for Linux,KSH for IBM AIX和Busybox的ASH for Android上testing了这一点,所以我认为可以在任何类似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" gzip -cd "$X" | xz -9c > "${X%.gz}.xz"

试着把命令放在花括号中,像这样:

 {command1 & ; command2 & ; command3 & ; } 

这不会创build一个子shell,而是在后台执行一组命令。

HTH

我不知道为什么没有人回答正确的解决scheme:

 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` 

 system "some command" 

输出相同的内容到标准输出,但第一个有更高的开销,因为Perl必须捕获所有的“ some command ”的输出

在for循环中分叉:

for i in x; do ((a; b; c;)&); done

例:

for i in 500 300 100; do ((printf "Start $i: "; date; dd if=/dev/zero of=testfile_$i bs=1m count=$i 2>/dev/null; printf "End $i: "; date;)&) && sleep 1; done

在子shell中运行命令:

 (command1 ; command2 ; command3) & 

以防万一某人仍然感兴趣,你可以做到这一点,而不需要像这样调用一个子shell:

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

您可以使用GNU parallel命令parallel运行作业。 更安全的是更快。

我的猜测是,你正试图从源到目的地复制多个大文件。 为此,您可以使用以下语句并行执行此操作。

 $ ls *|parallel -kj0 --eta 'cp {} /tmp/destination' 

正如我们已经使用-j0选项,所有的文件将被并行复制。 如果您需要减less并行进程的数量,则可以使用-j<n> ,其中<n>是要执行的并行进程的数量。

Parallel还会收集进程的输出,并以顺序的方式(使用-k选项)报告其他作业控制机制不能执行的操作。

--eta选项会给你正在进行的过程的细节统计。 所以我们可以知道这个过程是如何完成的,需要多长时间才能完成。