Como posso executar vários comandos que possuem & em uma linha de comando?

12

Eu encontrei um problema de dor de cabeça.

Quero executar vários comandos em segundo plano, então quero iniciá-los no bash, um por um. É fácil iniciar um comando no linux shell em segundo plano, assim:

myCommand &

Também é fácil iniciar vários comandos, assim:

myCommand1 && myCommand2

ou

myCommand1 ; myCommand2

Mas se eu quiser executar vários comandos em segundo plano, tentei o seguinte formato de comando, mas falhei:

myCommand1 & && myCommand2 &

ou

myCommand1 & ; myCommand2 &

Ambos os formatos falham. Como posso executar vários comandos que possuem &uma linha de comando?

Relógio ZHONG
fonte
2
Coloque-os em um script e execute-o em segundo plano
Panther
Pantera, parece que usar () poderia ajudar a corrigir esse problema muito mais facilmente do que usar um script. Vamos tentar fazer pleno uso dos recursos fornecidos pelo próprio shell em primeiro lugar, em vez de compor o que queremos sozinhos. Mas é claro que o uso de scripts também pode corrigir esse problema. Obrigado mesmo assim.
Clock ZHONG
E se eu quiser executar um 'tail -f <file1>> <file2>' seguido de 'empregos -L', que é novamente seguido por 'renegar -h% 1'
akskap

Respostas:

24

Usar ().

Se você deseja executá-los sequencialmente:

(myCommand1; myCommand2) &

ou

(myCommand1 &) && (myCommand2 &)

Se você deseja que eles funcionem paralelamente:

myCommand1 & myCommand2 &

No bash, você também pode usar isso (o espaço atrás de {e o; são obrigatórios):

{ myCommand1 && myCommand2; } &
Rinzwind
fonte
3
(myCommand1 &) && (myCommand2 &)funcionará myCommand2mesmo se myCommand1falhar.
terdon
() poderia ajudar o bash a distinguir os & e &&. Portanto, basta usar () para separar a unidade de execução quando quisermos usar o & e && para reunir.
Clock ZHONG
16

Suponho que você queira o seguinte:

myCommand1 & myCommand2 &

Isso inicia myCommand1e o envia para o plano de fundo conforme é seguido por "e comercial"; em seguida, inicia myCommand2e envia imediatamente também para o plano de fundo, liberando o shell novamente.

Listas

Para um melhor entendimento, você pode substituir o pipeline por comando aqui.

Uma lista é uma sequência de um ou mais pipelines separados por um dos operadores ; , & , && , ou || e opcionalmente encerrado por um de ; , & ou .

Se um comando é finalizado pelo operador de controle & , o shell executa o comando em segundo plano em uma subshell. O shell não espera o comando terminar e o status de retorno é 0. Comandos separados por a ; são executados sequencialmente; o shell aguarda que cada comando termine por sua vez. O status de retorno é o status de saída do último comando executado.

As listas AND e OR são sequências de um ou mais pipelines separados pelos && e || operadores de controle, respectivamente.
Fonte:man bash

Vamos dividir isso em exemplos. Você pode criar uma lista combinando comandos e separando-os com um destes ; & && ||:

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

Você pode encerrar listas com um destes: ; & <newline>.
Normalmente você executa um comando ou uma lista pressionando Enter, que é igual <newline>. O ponto e vírgula ;serve ao mesmo propósito, especialmente em scripts. E comercial, &no entanto, inicia o (s) comando (s) em um subshell em segundo plano, liberando imediatamente o shell.

Você pode usar ()colchetes redondos ou cacheados {}para listas de grupos adicionais, a diferença é que os colchetes geram um subshell e os cacheados não. Os colchetes precisam de um espaço após o primeiro e um ponto-e-vírgula ou uma nova linha antes do colchete de fechamento. Por exemplo:

# 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 &

Isso pode ser bastante complicado, se você não tiver certeza do uso truee falsetestar se a construção funciona conforme o esperado:

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

Job Control

O jobscomando exibe uma lista dos trabalhos em segundo plano que estão em execução ou foram concluídos recentemente no shell atual. Existem vários atalhos de teclado e comandos para controle de tarefas:

  • Ctrl+ Zdigita o caractere de suspensão que faz com que o processo atualmente em execução no primeiro plano seja parado, ele não é finalizado, mas permanece na jobslista
  • Ctrl+ Ydigita o caractere de suspensão atrasada que faz com que o processo atualmente em execução no primeiro plano seja interrompido quando ele tenta ler a entrada do terminal
  • fg= %coloca um processo em primeiro plano iniciando-o, se necessário, você pode especificar o processo da seguinte maneira:

     %       # 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= %&coloca um processo em segundo plano, iniciando-o, se necessário:

     %&      # 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 aguarda a conclusão de um processo em segundo plano e retorna seu status de encerramento:

     wait %1 # 1st process in the jobs list

    Imagine que você iniciou um processo demorado ( jobsrevela o número 3) e depois percebe que deseja que o computador seja suspenso quando terminar, além de echouma mensagem se o processo não tiver êxito:

     wait %3 || echo failed ; systemctl suspend
sobremesa
fonte
Mas é importante ter cuidado com o &&, pois depende do que o comando retornar ; portanto, precisamos ter certeza de que o que chamamos realmente retorna algo bash considera um valor verdadeiro ..?
mathreadler
@mathreadler A menos que você esteja falando de algum script de usuário mal elaborado, o valor de saída é muito bem definido (veja man bash) e amplamente utilizado exatamente como se destina AFAIK - nunca experimentei nada de estranho.
dessert
exatamente, é preciso ter cuidado com os scripts de usuários mal elaborados. Eles existem e podem ser dolorosos para encontrar esses erros. Askubuntu não me permite "@ sobremesa" você.
mathreadler
Ah, tudo bem, isso faz sentido agora que você mencionou.
mathreadler