Как я могу запустить несколько команд, которые имеют & в одной командной строке?

12

Я столкнулся с проблемой головной боли.

Я хочу выполнять несколько команд в фоновом режиме, поэтому я хочу запускать их в bash одну за другой. Легко запустить одну команду в оболочке linux в фоновом режиме, вот так:

myCommand &

Также легко запустить несколько команд, вот так:

myCommand1 && myCommand2

или

myCommand1 ; myCommand2

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

myCommand1 & && myCommand2 &

или

myCommand1 & ; myCommand2 &

Оба формата не работают. Как я могу запустить несколько команд, которые находятся &в одной командной строке?

Часы ZHONG
источник
2
Поместите их в сценарий и запустите сценарий в фоновом режиме
Panther
Пантера, кажется, использование () может помочь решить эту проблему намного проще, чем использование скрипта. Давайте сначала попробуем в полной мере использовать возможности, предоставляемые самой оболочкой, вместо того, чтобы составлять то, что мы хотим сами. Но, конечно, использование скрипта также может решить эту проблему. Спасибо, в любом случае.
часы ZHONG
Что, если я хочу запустить 'tail -F <file1>> <file2>', а затем 'jobs -l', за которым снова следует 'disown -h% 1'
akskap

Ответы:

24

Используйте ().

Если вы хотите запустить их последовательно:

(myCommand1; myCommand2) &

или

(myCommand1 &) && (myCommand2 &)

Если вы хотите, чтобы они работали параллельно:

myCommand1 & myCommand2 &

В bash вы также можете использовать это (пробел за {и;; обязателен):

{ myCommand1 && myCommand2; } &
Rinzwind
источник
3
(myCommand1 &) && (myCommand2 &)будет работать, myCommand2даже если myCommand1не удалось.
тердон
() может помочь bash различать & и &&. Так что просто используйте () для разделения исполняющего модуля, когда мы хотим использовать & и && вместе.
Часы ZHONG
16

Я полагаю, вы хотите это:

myCommand1 & myCommand2 &

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

Списки

Для лучшего понимания вы можете заменить трубопровод с помощью команды здесь.

Список - это последовательность одного или нескольких конвейеров, разделенных одним из операторов ; , & , && или || и необязательно прекращается одним из ; , & , или ,

Если команда завершается оператором управления & , оболочка выполняет команду в фоновом режиме в подоболочке. Оболочка не ожидает завершения команды, и возвращается статус 0. Команды, разделенные символом a ; выполняются последовательно; оболочка ожидает завершения каждой команды по очереди. Статус возврата - это статус выхода последней выполненной команды.

Списки AND и OR являются последовательностями одного или нескольких конвейеров, разделенных символами && и || управляющие операторы соответственно.
Источник:man bash

Давайте разберем это на примеры. Вы можете создать список, комбинируя команды и разделяя их одним из них ; & && ||:

command1 ; command2  # runs sequentially
command1 && command2 # runs sequentially, runs command2 only if command1 succeeds
command1 || command2 # runs sequentially, runs command2 only if command1 fails
command1 & command2  # runs simultaneously

Вы можете прекратить списки с одним из них: ; & <newline>.
Обычно вы выполняете команду или список, нажимая Enter, что равно <newline>. Точка с запятой ;служит той же цели, особенно в сценариях. &Однако Ampersand запускает команду (-и) в подоболочке в фоновом режиме, немедленно выпуская оболочку.

Вы можете использовать круглые ()или фигурные скобки {}для дальнейшей группировки списков, с той разницей, что круглые скобки порождают подоболочки, а фигурные - нет. Кудрявые скобки требуют пробела после первой и точки с запятой или новой строки перед закрывающей скобкой. Например:

# if c1 succeeds start a shell in the background
# and run c2 and c3 sequentially inside it
c1 && ( c2 ; c3 ) & 
# run c1 and if it succeeds c2 sequentially as a group command
# if c1 or c2 fail run c3 in the background
{ c1 && c2 ;} || c3 &

Это может быть довольно сложно, если вы не уверены в том, что используете, trueи falseпроверить, работает ли конструкция должным образом:

$ { true && true ;} || echo 2
$ { true && false ;} || echo 2
2

Контроль работы

Команда jobsотображает список фоновых заданий, которые выполняются или недавно были завершены в текущей оболочке. Существует несколько сочетаний клавиш и команд для управления заданиями:

  • Ctrl+ Zвводит символ приостановки, который вызывает остановку процесса, запущенного в данный момент на переднем плане, он не прерывается, но остается в jobsсписке
  • Ctrl+ Yвводит символ отложенной приостановки, который вызывает остановку процесса, запущенного в данный момент на переднем плане, когда он пытается прочитать ввод с терминала
  • fg= %выводит процесс на передний план, запуская его при необходимости, вы можете указать процесс следующим образом:

     %       # last process in the jobs list
     %1      # 1st process in the jobs list
     %abc    # process beginning with the string “abc”
     %?abc   # process containing the string “abc” anywhere
  • bg= %&переводит процесс в фоновый режим, запуская его при необходимости:

     %&      # last process in the jobs list
     %1&     # 1st process in the jobs list
     %abc&   # process beginning with the string “abc”
     %?abc&  # process containing the string “abc” anywhere
  • wait ожидает завершения фонового процесса и возвращает его статус завершения:

     wait %1 # 1st process in the jobs list

    Представьте, что вы запустили длительный процесс ( jobsпоказывает, что это номер 3), а затем поняли, что хотите, чтобы компьютер был приостановлен после его завершения, плюс echoсообщение, если процесс не удался:

     wait %3 || echo failed ; systemctl suspend
Десерт
источник
Но важно быть осторожным с &&, это зависит от того, что возвращает команда , поэтому мы должны быть уверены, что то, что мы вызываем, действительно возвращает что-то, что bash считает истинным значением ..?
mathreadler
@mathreadler Если вы не говорите о каком-то плохо написанном пользовательском скрипте, значение выхода очень хорошо определено (см. man bash) и широко используется именно так, как задумано AFAIK - я никогда не сталкивался с чем-то странным.
десерт
точно следует быть осторожным с плохо написанными пользовательскими скриптами. Они существуют и могут быть боль, чтобы найти такие ошибки. Askubuntu не позволяет мне "@ десерт" вас.
mathreadler
Ах, хорошо, это имеет смысл теперь, когда вы упомянули это.
mathreadler