bash:在后台启动多个链式命令
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/161252/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
bash: start multiple chained commands in background
提问by Mad_Ady
I'm trying to run some commands in paralel, in background, using bash. Here's what I'm trying to do:
我正在尝试使用 bash 在后台并行运行一些命令。这是我想要做的:
forloop {
//this part is actually written in perl
//call command sequence
print `touch .file1.lock; cp bigfile1 /destination; rm .file1.lock;`;
}
The part between backticks (``) spawns a new shell and executes the commands in succession. The thing is, control to the original program returns only after the last command has been executed. I would like to execute the whole statement in background (I'm not expecting any output/return values) and I would like the loop to continue running.
反引号 (``) 之间的部分产生一个新的 shell 并连续执行命令。问题是,只有在执行完最后一个命令后,对原始程序的控制才会返回。我想在后台执行整个语句(我不希望有任何输出/返回值)并且我希望循环继续运行。
The calling program (the one that has the loop) would not end until all the spawned shells finish.
调用程序(具有循环的程序)在所有生成的 shell 完成之前不会结束。
I could use threads in perl to spawn different threads which call different shells, but it seems an overkill...
我可以在 perl 中使用线程来生成调用不同 shell 的不同线程,但这似乎有点矫枉过正……
Can I start a shell, give it a set of commands and tell it to go to the background?
我可以启动一个shell,给它一组命令并告诉它进入后台吗?
采纳答案by Hugh Allen
I haven't tested this but how about
我还没有测试过这个但是怎么样
print `(touch .file1.lock; cp bigfile1 /destination; rm .file1.lock;) &`;
The parentheses mean execute in a subshell but that shouldn't hurt.
括号表示在子shell 中执行,但这不应该受到伤害。
回答by Mad_Ady
Thanks Hugh, that did it:
谢谢休,做到了:
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:~$
The other ideas don't work because they start each command in the background, and not the command sequence (which is important in my case!).
其他想法不起作用,因为它们在后台启动每个命令,而不是命令序列(这对我来说很重要!)。
Thank you again!
再次感谢你!
回答by lechup
Another way is to use the following syntax:
另一种方法是使用以下语法:
{ command1; command2; command3; } &
wait
Note that the &
goes at the end of the command group, not after each command. The semicolon after the final command is necessary, as are the space after the first bracket and before the final bracket. The wait
at the end ensures that the parent process is not killed before the spawned child process (the command group) ends.
请注意,在&
命令组的末尾,而不是在每个命令之后。最后一个命令后的分号是必需的,第一个括号后和最后一个括号前的空格也是必要的。所述wait
在端部保证了父进程未衍生的子进程(命令组)的端部之前死亡。
You can also do fancy stuff like redirecting stderr
and stdout
:
你还可以做一些花哨的事情,比如重定向stderr
和stdout
:
{ command1; command2; command3; } 2>&2 1>&1 &
Your example would look like:
您的示例如下所示:
forloop() {
{ touch .file1.lock; cp bigfile1 /destination; rm .file1.lock; } &
}
# ... do some other concurrent stuff
wait # wait for childs to end
回答by GavinCattell
for command in $commands
do
"$command" &
done
wait
The ampersand at the end of the command runs it in the background, and the wait
waits until the background task is completed.
命令末尾的&符号在后台运行它,并wait
等待后台任务完成。
回答by NVRAM
GavinCattellgot the closest (for bash, IMO), but as Mad_Ady pointed out, it would not handle the "lock" files. This should:
GavinCattell得到了最接近的(对于 bash,IMO),但正如 Mad_Ady 指出的那样,它不会处理“锁定”文件。这应该:
If there are other jobs pending, the waitwill wait for those, too. If you need to wait for onlythe copies, you can accumulate those PIDs and wait for only those. If not, you could delete the 3 lines with "pids" but it's more general.
如果还有其他待处理的作业,等待也会等待这些作业。如果您需要等待只是副本,你可以积累的PID和等待只。如果没有,您可以删除带有“pids”的 3 行,但它更通用。
In addition, I added checking to avoid the copy altogether:
此外,我添加了检查以完全避免复制:
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
Incidentally, it looks like you're copying new files to an FTP repository (or similar). If so, you couldconsider a copy/rename strategy instead of the lock files (but that's another topic).
顺便说一句,您似乎正在将新文件复制到 FTP 存储库(或类似存储库)。如果是这样,您可以考虑使用复制/重命名策略而不是锁定文件(但这是另一个主题)。
回答by slm
The facility in bash that you're looking for is called Compound Commands
. See the man page for more info:
您正在寻找的 bash 工具称为Compound Commands
. 有关更多信息,请参阅手册页:
Compound Commands A compound command is one of the following:
(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.
复合命令 复合命令是以下之一:
(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.
There are others, but these are probably the 2 most common types. The first, the parens, will run a list of command in series in a subshell, while the second, the curly braces, will a list of commands in series in the current shell.
还有其他的,但这些可能是最常见的两种类型。第一个,括号,将在子 shell 中运行一系列命令列表,而第二个,花括号,将在当前 shell 中运行一系列命令列表。
parens
父母
% ( date; sleep 5; date; )
Sat Jan 26 06:52:46 EST 2013
Sat Jan 26 06:52:51 EST 2013
curly braces
大括号
% { date; sleep 5; date; }
Sat Jan 26 06:52:13 EST 2013
Sat Jan 26 06:52:18 EST 2013
回答by Radu Simionescu
run the commands in a subshell:
在子shell中运行命令:
(command1 ; command2 ; command3) &
回答by Eliseo Carrasco
Run the command by using an at job:
使用 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
The result will be sent to your account by mail.
结果将通过邮件发送到您的帐户。
回答by RAKK
I stumbled upon this thread here and decided to put together a code snippet to spawn chained statements as background jobs. I tested this on BASH for Linux, KSH for IBM AIX and Busybox's ASH for Android, so I think it's safe to say it works on anyBourne-like shell.
我在这里偶然发现了这个线程,并决定将代码片段放在一起以生成链式语句作为后台作业。我在适用于 Linux 的 BASH、适用于 IBM AIX 的 KSH 和适用于 Android 的 Busybox 的 ASH 上对此进行了测试,所以我认为可以肯定地说它适用于任何类似 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;
This code runs a number of background jobs up to a certain limit of concurrent jobs. You can use this, for example, to recompress a lot of gzipped files with xz
without having a huge bunch of xz
processes eat your entire memory and make your computer throw up: in this case, you use *
as the for
's list and the batch job would be gzip -cd "$X" | xz -9c > "${X%.gz}.xz"
.
此代码运行多个后台作业,最多可运行一定数量的并发作业。例如,您可以使用它来重新压缩大量 gzipped 文件,xz
而不xz
会让大量进程占用您的整个内存并让您的计算机崩溃:在这种情况下,您使用*
asfor
的列表,批处理作业将是gzip -cd "$X" | xz -9c > "${X%.gz}.xz"
。
回答by Zsolt Botykai
Try to put commands in curly braces with &s, like this:
尝试将命令放在带有 &s 的花括号中,如下所示:
{command1 & ; command2 & ; command3 & ; }
This does not create a sub-shell, but executes the group of commands in the background.
这不会创建子外壳,而是在后台执行命令组。
HTH
HTH