2010-02-14 10 views
10

Estoy escribiendo un pequeño script, que creará archivos en el hilo principal y después de que se complete cada archivo, se creará un nuevo hilo llamando a la función que se encargaría de cargar estos archivos. El motivo por el que quiero que se cargue en segundo plano es para poder crear otro archivo mientras se cargan los archivos anteriores.Enlazado de Bash: esperar a que terminen todos los hilos de trabajo no funciona?

El problema que estoy teniendo está al final del script. Es decir, el hilo principal no espera a que todos los subprocesos suban antes de salir. Mira el siguiente script simplificado (He quitado/cambiado partes del código no relacionados con el problema)

function func { 
for files in /home/somewhere/ 
    do 
    echo "Uploading $1" & 
    done 
wait 
} 

find /home/some/path -type f | while read filename ; do 
    echo "Creating archive of $filename" 
    func $somevariable & 
done 

wait 

Todo está ejecutando muy bien hasta que se cree el último archivo, entonces el script termina antes de que todos func hilos terminan, dejando muchos archivos no cargados.

Gracias por sus ideas.

+0

@Andrew: ¿qué sistema operativo está usando? Conozco algunas compilaciones de Solaris que tienen un error de espera como este. –

+0

@martin clayton: Estoy usando Ubuntu Server 9.10 – Gargauth

Respuesta

11

Actualización: buenos puntos en el comentario.

Por lo tanto, en una segunda mirada, resulta que el problema es la subcapa creada por la tubería en el ciclo. Es una buena forma de estructurar el script, pero necesita hacer la espera final en el shell que separó las tareas en segundo plano.

Así que hacer algo como esto:

find /home/some/path -type f | (while read filename; do 
    echo "Creating archive of $filename" 
    func $somevariable & 
    done 
    wait 
) 
+1

Gracias, pero si elimino '&' de 'function func', esperaría a que se completara la función, ¿no? Además, tengo la función de carga en bucle, de modo que 4 archivos se cargan a la vez. Para eso necesito que ese bucle continúe incluso después de ejecutar los comandos de carga. EDITAR: también tengo 'wait' en la función de shell. – Gargauth

+0

Gracias de nuevo por la actualización :) Creo * que hizo el truco. Haré algunas pruebas más. – Gargauth

-1

Puede hacer un bucle hasta que el comando jobs no devuelva nada como método alternativo.

3

Si ejecuta wait sin argumentos, se supone que esperar a que actualmente los procesos hijo activos para completar.

Es probable que el problema sea que "todos los procesos secundarios actualmente activos" no significa lo que cree que significa en este contexto. En particular, si crea tuberías en una subcadena, no está del todo claro si se esperarían en el shell primario.

Sospecho que wait realmente solo espera procesos/tuberías que aparecen en la salida de jobs. Pruebe algunos experimentos ...

Una posible alternativa puede ser capturar los id. De procesos secundarios y hacer una llamada wait n para cada id.

6

Tricky! El problema es que este bloque

find /home/some/path -type f | while read filename ; do 
    ... 
done 

Crea una subshell. Los trabajos func $ algunavariables se crean en esa subcadena. El shell primario ve que todos los trabajos en segundo plano creados han finalizado, no hace un seguimiento de los trabajos en segundo plano creados por las subcélulas que generó.

La solución más fácil es crear sus trabajos en segundo plano desde el shell principal en su lugar. Puede evitar la creación de un subnivel al no utilizar una tubería:

while read filename ; do 
    ... 
done < <(find /home/some/path -type f) 

Bueno, que crea un subnivel --- para el hallazgo --- pero el bloque, mientras que ya no está en un subnivel.

Tenga en cuenta que lo anterior solo funciona bajo bash. (No sé sobre ksh o zsh, quizás también funcione allí. Pero no funcionará bajo cenizas y otros derivados sh).

Cuestiones relacionadas