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

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,给它一组命令并告诉它去后台吗?

有帮助吗?

解决方案

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

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

请注意,&在命令组的末尾,而不是在每个命令之后。最后一个命令之后的分号是必要的,第一个括号之后和最后一个括号之前的空格也是必需的。最后的wait确保在生成的子进程(命令组)结束之前不会终止父进程。

你也可以做一些像重定向stderrstdout

这样的花哨的东西
{ 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

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

GavinCattell 得到了最接近的(对于bash ,IMO),但正如Mad_Ady指出的那样,它不会处理<!> quot; lock <!>;文件。这应该:

如果还有其他待处理作业,等待也将等待这些作业。如果您需要等待副本,您可以累积这些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存储库(或类似文件)。如果是这样,你可以考虑复制/重命名策略而不是锁定文件(但这是另一个主题)。

您正在寻找的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.

还有其他一些,但这些可能是最常见的两种类型。第一个是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上进行了测试,所以我认为它可以安全地用于任何 Bourne-like 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;

此代码运行许多后台作业,直到并发作业的某个限制。例如,你可以使用它来重新压缩大量的gzip压缩文件,而不需要大量的xz进程占用你的整个内存并让你的计算机瘫痪:在这种情况下,你使用* as for的列表和批处理作业将是gzip -cd "$X" | xz -9c > "${X%.gz}.xz"

在子shell中运行命令:

(command1 ; command2 ; command3) &

尝试使用<!> amp; s将命令放在花括号中,如下所示:

{command1 & ; command2 & ; command3 & ; }

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

HTH

我不知道为什么没有人回答适当的解决方案:

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"

将相同的内容输出到stdout,但是第一个具有更高的开销,因为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来做到这一点:

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

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

我的猜测是你试图将多个大文件从源复制到目标。为此,您可以与以下声明并行执行此操作。

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

由于我们使用了-j0选项,所有文件将被并行复制。如果您需要减少并行进程的数量,那么您可以使用-j<n>其中<n>是要执行的并行进程数。

Parallel还将收集流程的输出并以顺序方式(带有-k选项)报告,其他作业控制机制无法做到。

--eta选项将为您提供正在进行的流程的详细统计信息。因此,我们可以知道该过程的完成情况以及完成所需的时间。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top