Dilema de subshell While-loop en Bash

Quiero calcular todos los archivos * bin dentro de un directorio determinado. Inicialmente estaba trabajando con un for-loop :

 var=0 for i in *ls *bin do perform computations on $i .... var+=1 done echo $var 

Sin embargo, en algunos directorios hay demasiados archivos que dan como resultado un error: Argument list too long

Por lo tanto, estaba intentándolo con un while-loop :

 var=0 ls *.bin | while read i; do perform computations on $i var+=1 done echo $var 

El problema ahora es usar las subcapas de tubería creadas. Por lo tanto, echo $var devuelve 0 .
¿Cómo puedo lidiar con este problema?
El código original:

 #!/bin/bash function entropyImpl { if [[ -n "$1" ]] then if [[ -e "$1" ]] then echo "scale = 4; $(gzip -c ${1} | wc -c) / $(cat ${1} | wc -c)" | bc else echo "file ($1) not found" fi else datafile="$(mktemp entropy.XXXXX)" cat - > "$datafile" entropy "$datafile" rm "$datafile" fi return 1 } declare acc_entropy=0 declare count=0 ls *.bin | while read i ; do echo "Computing $i" | tee -a entropy.txt curr_entropy=`entropyImpl $i` curr_entropy=`echo $curr_entropy | bc` echo -e "\tEntropy: $curr_entropy" | tee -a entropy.txt acc_entropy=`echo $acc_entropy + $curr_entropy | bc` let count+=1 done echo "Out of function: $count | $acc_entropy" acc_entropy=`echo "scale=4; $acc_entropy / $count" | bc` echo -e "===================================================\n" | tee -a entropy.txt echo -e "Accumulated Entropy:\t$acc_entropy ($count files processed)\n" | tee -a entropy.txt 

El problema es que el ciclo while se ejecuta en una subcadena. Después de que termine el ciclo while, la copia de var de var se descarta y la var original del padre (cuyo valor no se modifica) se repite.

Una forma de solucionar esto es mediante el uso de la sustitución de procesos como se muestra a continuación:

 var=0 while read i; do # perform computations on $i ((var++)) done < <(find . -type f -name "*.bin" -maxdepth 1) 

Eche un vistazo a BashFAQ / 024 para otras soluciones.

Tenga en cuenta que también he reemplazado ls con find porque no es una buena práctica analizar ls .

Una solución compatible con POSIX sería usar una tubería (archivo p). Esta solución es muy agradable, portátil y POSIX, pero escribe algo en el disco duro.

 mkfifo mypipe find . -type f -name "*.bin" -maxdepth 1 > mypipe & while read line do # action done < mypipe rm mypipe 

Tu tubería es un archivo en tu disco duro. Si quiere evitar tener archivos inútiles, no olvide eliminarlos.

Esto también se puede hacer con un bucle for:

 var=0; for file in `find . -type f -name "*.bin" -maxdepth 1`; do # perform computations on "$i" ((var++)) done echo $var