bash: запускать несколько цепочек команд в фоновом режиме - PullRequest
43 голосов
/ 02 октября 2008

Я пытаюсь запустить некоторые команды в параллельном режиме, в фоновом режиме, используя bash. Вот что я пытаюсь сделать:

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

Часть между обратными галочками (``) порождает новую оболочку и последовательно выполняет команды. Дело в том, что управление исходной программой возвращается только после выполнения последней команды. Я хотел бы выполнить весь оператор в фоновом режиме (я не ожидаю каких-либо выходных / возвращаемых значений) и хотел бы, чтобы цикл продолжал выполняться.

Вызывающая программа (та, которая имеет цикл) не завершится, пока не завершатся все порожденные оболочки.

Я мог бы использовать потоки в Perl для создания разных потоков, которые вызывают разные оболочки, но это кажется излишним ...

Могу ли я запустить оболочку, дать ей набор команд и сказать ей перейти в фоновый режим?

Ответы [ 14 ]

29 голосов
/ 02 октября 2008

Я не проверял это, но как насчет

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

Скобки означают выполнение в подоболочке, но это не должно повредить.

19 голосов
/ 02 октября 2008

Спасибо, Хью, что сделал это:

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

Другие идеи не работают, потому что они запускают каждую команду в фоновом режиме, а не последовательность команд (что важно в моем случае!).

Еще раз спасибо!

18 голосов
/ 26 сентября 2013

Другой способ - использовать следующий синтаксис:

{ 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
14 голосов
/ 02 октября 2008
for command in $commands
do
    "$command" &
done
wait

Амперсанд в конце команды запускает его в фоновом режиме, а wait ожидает завершения фоновой задачи.

5 голосов
/ 05 ноября 2009

GavinCattell получил ближайший (для bash, IMO), но, как указал Mad_Ady, он не будет обрабатывать файлы "блокировки". Это должно:

Если есть другие ожидающие работы, wait также будет их ждать. Если вам нужно дождаться только копий, вы можете накапливать эти PID и ждать только те. Если нет, то вы можете удалить 3 строки с помощью «pids», но это более общий характер.

Кроме того, я добавил проверку, чтобы вообще избежать копирования:

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-хранилище (или подобное). Если это так, вы могли бы рассмотреть стратегию копирования / переименования вместо файлов блокировки (но это уже другая тема).

3 голосов
/ 26 января 2013

Средство в 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.

Есть и другие, но это, вероятно, 2 наиболее распространенных типа. Первый, parens, будет последовательно запускать список команд в подоболочке, а второй, фигурные скобки, - список последовательных команд в текущей оболочке.

1011 * круглые скобки * % ( 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
2 голосов
/ 19 ноября 2016

запустить команды в подоболочке:

(command1 ; command2 ; command3) &
2 голосов
/ 09 апреля 2014

Я наткнулся на эту тему здесь и решил собрать фрагмент кода для порождения цепочек операторов в качестве фоновых заданий. Я проверил это на BASH для Linux, KSH для IBM AIX и Busybox ASH для Android, поэтому я думаю, что можно с уверенностью сказать, что он работает на любой Борновоподобной оболочке.

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 без огромного количества процессов xz, которые поглощают всю вашу память и заставляют ваш компьютер загружаться: в этом случае вы используете * как список for и пакетное задание будут gzip -cd "$X" | xz -9c > "${X%.gz}.xz".

2 голосов
/ 13 сентября 2012

Запустите команду, используя задание 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

Результат будет отправлен на ваш счет по почте.

1 голос
/ 01 ноября 2014

Форкинг для цикла:

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

...