баш:запустить несколько связанных команд в фоновом режиме

StackOverflow https://stackoverflow.com/questions/161252

  •  03-07-2019
  •  | 
  •  

Вопрос

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

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

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

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

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

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

Это было полезно?

Решение

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

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

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

Другие советы

Спасибо, Хью, получилось:

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 в конце гарантирует, что родительский процесс не будет завершен до завершения порожденного дочернего процесса (группы команд).

Вы также можете делать такие необычные вещи, как перенаправление 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
for command in $commands
do
    "$command" &
done
wait

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

Гэвин Кеттелл получил самый близкий (для bash, IMO), но, как указал Mad_Ady, он не будет обрабатывать файлы «блокировки».Это должно:

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

Объект в 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 наиболее распространенных типа.Первые, круглые скобки, будут последовательно запускать список команд в подоболочке, а вторые, фигурные скобки, будут последовательно запускать список команд в текущей оболочке.

скобки

% ( 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 job:

# 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 для Linux, KSH для IBM AIX и ASH Busybox для 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;

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

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

(command1 ; command2 ; command3) &

Попробуйте поместить команды в фигурные скобки с помощью &s, например:

{command1 & ; command2 & ; command3 & ; }

При этом не создается подоболочка, а выполняется группа команд в фоновом режиме.

ХТХ

Я не знаю, почему никто не ответил правильным решением:

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

На всякий случай, если кому-то все еще интересно, вы можете сделать это без вызова подоболочки следующим образом:

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