Подтвердить что ты не робот

Bash: запуск нескольких цепочечных команд в фоновом режиме

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

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

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

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

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

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

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

[email protected]:~$ (echo "started"; sleep 15; echo "stopped")
started
stopped
[email protected]:~$ (echo "started"; sleep 15; echo "stopped") &
started
[1] 7101
[email protected]:~$ stopped

[1]+  Done                    ( echo "started"; sleep 15; echo "stopped" )
[email protected]:~$ 

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

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

Ответ 3

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

{ 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

Ответ 4

for command in $commands
do
    "$command" &
done
wait

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

Ответ 5

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

Ответ 6

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

круглые скобки

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

Ответ 7

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

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

Ответ 8

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

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;

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

Ответ 9

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

(command1 ; command2 ; command3) &

Ответ 10

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

{command1 & ; command2 & ; command3 & ; }

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

НТН

Ответ 11

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

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

Ответ 12

Викинг в цикле 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

Ответ 13

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

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

Ответ 14

Вы можете использовать команду GNU parallel для параллельной работы заданий. Это безопаснее быстрее.

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

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

Как мы использовали параметр -j0, все файлы будут скопированы параллельно. В случае, если вам нужно уменьшить количество параллельных процессов, вы можете использовать -j<n>, где <n> - количество параллельных процессов, которые должны быть выполнены.

Параллельно будет также собирать выходные данные процесса и сообщать об этом последовательным образом (с параметром -k), который не может выполнять другой механизм управления заданиями.

--eta опция даст вам подробную статистику процесса, который происходит. Таким образом, мы можем знать, как процесс может быть завершен и сколько времени потребуется для завершения.

Ответ 15

Вы можете передавать параметры в группу команд (с последовательными командами) и запускать их в фоновом режиме.

for hrNum in {00..11};
do
    oneHour=$((10#$hrNum + 0))
    secondHour=$((10#$hrNum + 12))
    { echo "$oneHour"; echo "$secondHour"; } &
    wait
done