¿Cómo puedo ejecutar múltiples comandos que tienen y en una línea de comando?

12

Me he encontrado con un problema de dolor de cabeza.

Quiero ejecutar múltiples comandos en segundo plano, así que quiero iniciarlos en bash uno por uno. Es fácil iniciar un comando en linux shell en segundo plano, así:

myCommand &

También es fácil iniciar múltiples comandos, así:

myCommand1 && myCommand2

o

myCommand1 ; myCommand2

Pero si quiero ejecutar múltiples comandos en segundo plano, probé el siguiente formato de comando, pero fallé:

myCommand1 & && myCommand2 &

o

myCommand1 & ; myCommand2 &

Ambos formatos fallan. ¿Cómo puedo ejecutar múltiples comandos que tienen &en una línea de comando?

Reloj ZHONG
fuente
2
Póngalos en un script y ejecute el script en segundo plano
Panther
Panther, parece que usar () podría ayudar a solucionar este problema mucho más fácilmente que usar un script. Intentemos hacer un uso completo de las características proporcionadas por el propio shell en primer lugar, en lugar de componer lo que queremos nosotros mismos. Pero, por supuesto, el uso del script también podría solucionar este problema. Gracias de cualquier manera.
Reloj ZHONG
¿Qué sucede si quiero ejecutar un 'tail -F <file1>> <file2>' seguido de 'jobs -l', que nuevamente es seguido por 'disown -h% 1'
Akskap

Respuestas:

24

Utilizar ().

Si desea ejecutarlos secuencialmente:

(myCommand1; myCommand2) &

o

(myCommand1 &) && (myCommand2 &)

Si quieres que se ejecuten en paralelo:

myCommand1 & myCommand2 &

En bash también puedes usar esto (el espacio detrás de {y the; son obligatorios):

{ myCommand1 && myCommand2; } &
Rinzwind
fuente
3
(myCommand1 &) && (myCommand2 &)se ejecutará myCommand2incluso si myCommand1falla.
terdon
() podría ayudar a bash a distinguir los & y &&. Así que solo use () para separar la unidad de ejecución cuando queramos usar el tog & &&&.
Reloj ZHONG
16

Supongo que quieres esto:

myCommand1 & myCommand2 &

Esto comienza myCommand1y lo envía al fondo ya que es seguido por un signo y luego comienza inmediatamente myCommand2y también lo envía al fondo, liberando así el shell nuevamente.

Liza

Para una mejor comprensión, puede sustituir la tubería por comando aquí.

Una lista es una secuencia de una o más tuberías separadas por uno de los operadores ; , & , && , o || , y opcionalmente terminado por uno de ; , & o .

Si el operador de control termina un comando & , el shell ejecuta el comando en segundo plano en un subshell. El shell no espera a que termine el comando y el estado de retorno es 0. Comandos separados por a ; se ejecutan secuencialmente; el shell espera que cada comando termine a su vez. El estado de retorno es el estado de salida del último comando ejecutado.

Las listas AND y OR son secuencias de una o más tuberías separadas por && y || operadores de control, respectivamente.
Fuente:man bash

Vamos a dividir eso en ejemplos. Puede crear una lista combinando comandos y separándolos con uno de estos ; & && ||:

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

Podrá poner fin a las listas con uno de los siguientes: ; & <newline>.
Normalmente ejecuta un comando o una lista presionando Enter, que es igual <newline>. El punto y coma ;tiene el mismo propósito, especialmente en los scripts. Ampersand, &sin embargo, inicia los comandos en un subshell en segundo plano, liberando inmediatamente el shell.

Puede usar ()corchetes redondos o rizados {}para agrupar más listas, la diferencia es que los corchetes generan una subshell y los rizados no. Los corchetes necesitan un espacio después del primero y un punto y coma o una nueva línea antes del corchete de cierre. Por ejemplo:

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

Esto puede ser bastante complicado, si no está seguro de usarlo truey falsepara probar si la construcción funciona como se esperaba:

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

Control de trabajo

El jobscomando muestra una lista de los trabajos en segundo plano que se están ejecutando o que se han terminado recientemente en el shell actual. Existen varios métodos abreviados de teclado y comandos para el control del trabajo:

  • Ctrl+ Zescribe el carácter de suspensión que hace que el proceso que se está ejecutando actualmente en primer plano se detenga, no finaliza, pero permanece en la jobslista
  • Ctrl+ Yescribe el carácter de suspensión retrasada que hace que el proceso que se está ejecutando actualmente en primer plano se detenga cuando intenta leer la entrada desde el terminal
  • fg= %pone un proceso en primer plano comenzando si es necesario, puede especificar el proceso de la siguiente manera:

     %       # 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= %&toma un proceso en segundo plano y lo inicia si es necesario:

     %&      # 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 espera a que finalice un proceso en segundo plano y devuelve su estado de finalización:

     wait %1 # 1st process in the jobs list

    Imagine que inició un proceso largo ( jobsrevela que es el número 3) y luego se da cuenta de que desea que la computadora se suspenda cuando finalice, más echoun mensaje si el proceso no tuvo éxito:

     wait %3 || echo failed ; systemctl suspend
postre
fuente
Pero es importante tener cuidado con &&, depende de lo que devuelva el comando , por lo que debemos asegurarnos de que lo que llamamos en realidad devuelve algo que bash considera un valor verdadero.
mathreadler
@mathreadler A menos que esté hablando de una secuencia de comandos de usuario mal hecha, el valor de salida está muy bien definido (ver man bash) y se usa ampliamente como se pretende AFAIK: nunca experimenté nada extraño.
postre
exactamente, uno debe tener cuidado con las secuencias de comandos de usuario mal hechas. Existen y puede ser un dolor encontrar tales errores. Askubuntu no me permite "@ postre" a usted.
mathreadler
Ah, está bien, eso tiene sentido ahora que lo mencionas.
mathreadler