¿Cómo almacenar información de archivos en una matriz?

¿Cómo almacenar información de archivos en una matriz?

Con esta parte del script puedo obtener la información necesaria sobre los archivos en mi directorio (y subdirectorios). La única información que necesito es la extensión y el tamaño del archivo.

for file in `find . -type f`; do
   size=$(stat -c '%s' ${file})
   file=$(echo "${file}" | awk -F/ '{print $NF}')
   ext=$(echo "${file}" | grep '..*\.' | awk -F. '{print $NF}' | grep '[A-Za-z0-9]')
if [ -z ${ext} ]; then
   echo "NOTE: no extention"
else
   EXTS="${EXTS}${ext}${newLine}"

Es sólo una parte del guión. Entonces mi pregunta es: ¿Cómo puedo poner esta información en una matriz? Quiero decir que quiero una matriz con elementos que se vea así:

 c/123 /12 h/90 /0 txt/0

donde c, h y txt son extensiones de archivo y 123, 12 y 0 son tamaños de archivo. Últimamente puedo trabajar por separado con tamaños y extensiones.
Espero haber dejado mi pregunta claramente. Lo siento por los errores. :)

Respuesta1

Primero,no lo hagasfor file in $(find …). Eso es muy frágil.

Ahora, puedes simplificar un poco tu código haciendo que find imprima los nombres de archivos y los tamaños juntos, usando -printf:

find . -type f -printf '%s.%f/'

Luego, puede utilizar awkpara procesar esta salida para obtener tamaños acumulativos por extensión. Tenga en cuenta que solía .separar el nombre del archivo ( %f) del tamaño ( %s), y agregué un /después de eso. Por lo tanto, puedo usarlo .como separador de campos en awk. Y dado que los únicos caracteres no permitidos en los nombres de archivos son /ASCII NUL, puedo usarlos de forma segura /como separador de registros.

Entonces:

awk -F. -v RS=/ 'NF > 2 {size[$NF] += $1; next}
  {size["/"] += $1}
END {for (i in size) {print i,"/",size[i]}'

Aquí, lo estoy usando /como índice si no hay extensión.

Conjunto:

$ find . -type f -printf '%s.%f/' | awk -F. -v RS=/ 'NF > 2 {size[$NF] += $1; next}
{size["/"] += $1}
END {for (i in size) {printf "%s/%d\n", i, size[i]}}'
h/780
md/2509
tex/23961
c/13557
//5109
txt/2349291
sh/1166
py/12248

Ahora, si tus extensiones no contienen espacios, puedes simplemente hacer:

my_array=( $(find . -type f -printf '%s.%f/' | awk -F. -v RS=/ 'NF > 2 {size[$NF] += $1; next} {size["/"] += $1} END {for (i in size) {printf "%s/%d\n", i, size[i]}}') )

O puede utilizar la sustitución de procesos y leer cada entrada en:

my_arr=()
while IFS='' read -r entry
do
    my_arr+=( "$entry" )
done < <(find . -type f -printf '%s.%f/' | awk -F. -v RS=/ 'NF > 2 {size[$NF] += $1; next} {size["/"] += $1} END {for (i in size) {printf "%s/%d\n", i, size[i]}}')

Como antes:

$ printf "%s\n" "${my_arr[@]}"
h/780
md/2509
tex/23961
c/13557
//5109
txt/2349291
sh/1166
py/12248

Respuesta2

Aquí hay un breve script de bash que está haciendo el trabajo:

i=0
while read -r -d $'\0' file
do
   size=$(stat -c '%s' ${file})
   ext=`basename $file | sed -re "s/^[^.]+.*\.//"`

   if [ -z "$ext" ] || [ "$ext" = "`basename $file`" ] ; then
      echo "NOTE: no extention ($file)"
   else
     extensions[$i]="$ext"
     sizes[$((i++))]=$size
   fi
done < <(find . -type f -print0)

for (( j=0 ; j<i; j++ )) do
  echo index: $j / extension: ${extensions[$j]} / size: ${sizes[$j]}
done

información relacionada