Bash espera por trabajos y limita el conteo de trabajos

Posible duplicado:
Cuatro tareas en paralelo … ¿cómo hago eso?

Supongamos un bucle que invoca un command

grep -v '#' < files.m3u | sed 's/\\\\/\/\//g' | sed 's/\\/\//g' | while read line do filename=$(basename "$line") avconv -i "$line" "${filename%.*}.wav" done 

Poner y después de avconv mantendrá avconv de desove para cada file. Ahora quiero hacer dos cosas:

  • Quiero limitar el número de processs generados a 4
  • Cuando termine el ciclo, quiero esperar a que el último esté listo

Related of "Bash espera por trabajos y limita el conteo de trabajos"

Puede recordar el PID de cada niño nuevo (marque $! Después de iniciarlo). Controle periódicamente cuántos niños todavía existen (por ejemplo, kill -0 ), si el número disminuye, genera uno nuevo, etc. Al final, simplemente wait .

Aquí hay un script que escribí por la misma razón:

 #! /bin/bash ## Tries to run commands in parallel. Commands are read from STDIN one ## per line, or from a given file specified by -f. ## Author: E. Choroba file='-' proc_num=$(grep -c ^processor'\b' /proc/cpuinfo) prefix=$HOSTNAME-$USER-$$ sleep=10 children=() names=() if [[ $1 =~ ^--?h(elp)?$ ]] ; then cat <<-HELP Usage: ${0##*/} [-f file] [-n max-processes] [-p tmp-prefix] -s [sleep] Defaults: STDIN for file $proc_num for max-processes (number of processors) $prefix for tmp-prefix $sleep for sleep interval HELP exit fi function debug () { if ((DEBUG)) ; then echo "$@" >&2 fi } function child_count () { debug Entering child_count "${children[@]}" child_count=0 new_children=() for child in "${children[@]}" ; do debug Trying $child if kill -0 $child 2>/dev/null ; then debug ... exists let child_count++ new_children+=($child) fi done children=("${new_children[@]}") echo $child_count debug Leaving child_count "${children[@]}" } while getopts 'f:n:p:s:' arg ; do case $arg in f ) file=$OPTARG ;; n ) proc_num=$((OPTARG)) ;; p ) prefix=$OPTARG;; s ) sleep=$OPTARG;; * ) echo "Warning: unknown option $arg" >&2 ;; esac done i=0 while read -r line ; do debug Reading $line name=$prefix.$i let i++ names+=($name) while ((`child_count`>=proc_num)) ; do sleep $sleep debug Sleeping done eval $line 2>$name.e >$name.o & children+=($!) debug Running "${children[@]}" done < <(cat $file) debug Loop ended wait cat "${names[@]/%/.o}" cat "${names[@]/%/.e}" >&2 rm "${names[@]/%/.o}" "${names[@]/%/.e}" 

De la pregunta vinculada , adaptada a su variación:

 sed -n -e '/#/!s,\\,/,g' files.m3u | xargs -d '\n' -I {} -P 4 \ sh -c 'line=$1; file=${line##*/}; avconv -i "$line" "${file%.*}.wav"' avconv_sh {} 

De nuevo, se requiere GNU xargs o alguna versión compatible con -d y -P . También tenga cuidado con los espacios adicionales en el file de input al principio y al final de la línea; este fragment los mantendrá si existen, lo que puede causar problemas.

Lo solucioné de esta manera. Gracias por los $! consejos

 #!/bin/bash children[0]=0 children[1]=0 children[2]=0 children[3]=0 i=0 grep -v '#' < files.m3u | sed 's/\\\\/\/\//g' | sed 's/\\/\//g' | while read line do filename=$(basename "$line") let k="$i%4" wait ${children[k]} avconv -i "$line" "${filename%.*}.wav" & children[k]=$! let i++ done wait ${children[0]} wait ${children[1]} wait ${children[2]} wait ${children[3]}