Pregunta

Estoy intentando ejecutar algunos comandos en paralelo, en segundo plano, usando bash.Esto es lo que estoy tratando de hacer:

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

La parte entre comillas invertidas (``) genera un nuevo shell y ejecuta los comandos en sucesión.La cuestión es que el control del programa original regresa solo después de que se haya ejecutado el último comando.Me gustaría ejecutar toda la declaración en segundo plano (no espero ningún valor de salida/retorno) y me gustaría que el bucle continúe ejecutándose.

El programa de llamada (el que tiene el bucle) no finalizará hasta que finalicen todos los shells generados.

Podría usar subprocesos en Perl para generar diferentes subprocesos que llamen a diferentes shells, pero parece una exageración...

¿Puedo iniciar un shell, darle un conjunto de comandos y decirle que pase a segundo plano?

¿Fue útil?

Solución

No he probado esto, pero ¿qué tal

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

Los paréntesis significan ejecutar en una subshell, pero eso no debería doler.

Otros consejos

Gracias Hugh, eso lo hizo:

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:~$ 

Las otras ideas no funcionan porque comienzan cada comando en segundo plano, y no la secuencia de comandos (¡lo cual es importante en mi caso!).

¡Gracias de nuevo!

Otra forma es utilizar la siguiente sintaxis:

{ command1; command2; command3; } &
wait

Tenga en cuenta que el & va al final del grupo de comandos, no después de cada comando.El punto y coma después del comando final es necesario, al igual que el espacio después del primer corchete y antes del corchete final.El wait al final garantiza que el proceso principal no se elimine antes de que finalice el proceso secundario generado (el grupo de comandos).

También puedes hacer cosas sofisticadas como redirigir stderr y stdout:

{ command1; command2; command3; } 2>&2 1>&1 &

Su ejemplo se vería así:

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

El ampersand al final del comando lo ejecuta en segundo plano, y el wait espera hasta que se complete la tarea en segundo plano.

GavinCattell obtuvo el más cercano (para bash , IMO), pero como señaló Mad_Ady, no manejaría el & "; Bloquear &"; archivos Esto debería:

Si hay otros trabajos pendientes, la espera también los esperará. Si necesita esperar solo las copias, puede acumular esos PID y esperar solo esos. Si no, puede eliminar las 3 líneas con & Quot; pids & Quot; pero es más general.

Además, agregué la comprobación para evitar la copia por completo:

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

Por cierto, parece que está copiando nuevos archivos a un repositorio FTP (o similar). Si es así, podría considerar una estrategia de copiar / renombrar en lugar de los archivos de bloqueo (pero ese es otro tema).

La instalación en bash que estás buscando se llama Compound Commands. Consulte la página del manual para obtener más información:

  

Comandos compuestos          Un comando compuesto es uno de los siguientes:

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

Hay otros, pero estos son probablemente los 2 tipos más comunes. El primero, los parens, ejecutará una lista de comandos en serie en un subshell, mientras que el segundo, las llaves, mostrará una lista de comandos en serie en el shell actual.

parens

% ( date; sleep 5; date; )
Sat Jan 26 06:52:46 EST 2013
Sat Jan 26 06:52:51 EST 2013

llaves rizadas

% { date; sleep 5; date; }
Sat Jan 26 06:52:13 EST 2013
Sat Jan 26 06:52:18 EST 2013

Ejecute el comando utilizando un trabajo 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

El resultado se enviará a su cuenta por correo.

Me topé con este hilo aquí y decidí armar un fragmento de código para generar declaraciones encadenadas como trabajos en segundo plano.Probé esto en BASH para Linux, KSH para IBM AIX y ASH de Busybox para Android, así que creo que es seguro decir que funciona en cualquier Concha tipo 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;

Este código ejecuta una cantidad de trabajos en segundo plano hasta un cierto límite de trabajos simultáneos.Puedes usar esto, por ejemplo, para recomprimir muchos archivos comprimidos con gzip. xz sin tener un montón de xz Los procesos consumen toda tu memoria y hacen que tu computadora vomite:en este caso se utiliza * como el forLa lista y el trabajo por lotes serían gzip -cd "$X" | xz -9c > "${X%.gz}.xz".

ejecuta los comandos en una subshell:

(command1 ; command2 ; command3) &

Intenta poner comandos en llaves con & amp; s, así:

{command1 & ; command2 & ; command3 & ; }

Esto no crea un sub-shell, pero ejecuta el grupo de comandos en segundo plano.

HTH

No sé por qué nadie respondió con la solución adecuada:

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;

Esto hace que Perl engendre hijos para ejecutar cada comando y le permite esperar a que todos los hijos se completen antes de continuar.

Por cierto,

print `some command`

y

system "some command"

genera el mismo contenido en stdout, pero el primero tiene una sobrecarga mayor, ya que Perl tiene que capturar todos los resultados de " some command " '

Bifurcación en un bucle for:

for i in x; do ((a; b; c;)&); done

Ejemplo:

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

En caso de que alguien todavía esté interesado, puede hacerlo sin llamar a una subshell como esta:

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

Puede usar el comando GNU parallel para ejecutar trabajos en paralelo. Es más seguro son más rápidos.

Supongo que está intentando copiar múltiples archivos grandes desde el origen al destino. Y para eso puede hacerlo en paralelo con la siguiente declaración.

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

Como hemos usado la opción -j0, todos los archivos se copiarán en paralelo. En caso de que necesite reducir el número de procesos paralelos, puede usar -j<n> donde <n> es el número de procesos paralelos que se ejecutarán.

Paralelo también recopilará el resultado del proceso y lo informará de manera secuencial (con la opción -k) que otro mecanismo de control de trabajo no puede hacer.

La opción

--eta le dará estadísticas detalladas del proceso que está sucediendo. Entonces podemos saber cómo se ha completado el proceso y cuánto tiempo llevará terminarlo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top