¿Cómo extraer caracteres entre el primer y segundo guión bajo de los nombres de archivos y contar dichos archivos en la carpeta de Linux?

¿Cómo extraer caracteres entre el primer y segundo guión bajo de los nombres de archivos y contar dichos archivos en la carpeta de Linux?

Me gustaría extraer caracteres entre el primer y segundo guión bajo de los nombres de archivos en una carpeta y contar ese tipo de archivos presentes en ella.

La carpeta contiene archivos en un formato particular como:

2305195303310_ABC_A08_1378408840043.hl7

2305195303310_ABC_A08_1378408840043.hl7
Q37984932T467566261_DEF_R03_1378825633215.hl7
37982442T467537201_DEF_R03_1378823455384.hl7
37982442T467537201_MNO_R03_1378823455384.hl7
2305195303310_ABC_A08_1378408840053.hl7
Q37984932T467566261_DEF_R03_1378825633215.hl7
37982442T467537201_MNO_R03_1378823455384.hl7

Etcétera…

La salida del script debería darme un resultado como:

ABC 3
DEF 3
MNO 2

Respuesta1

ls | cut -d_ -f2 | sort | uniq -c

Respuesta2

Puedes hacer esto de la forma clásica *nix, encadenando pequeños comandos. Primero, busque los archivos de interés, para ello puede usar shellglobo:

for i in *_*_*; do echo "$i"; done

Ese comando imprimirá todos los archivos en el directorio actual cuyo nombre contenga dos guiones bajos. Para extraer la cadena entre esos guiones bajos, puedes usarcut, diciéndole que lo use _como delimitador de campo e imprima el segundo campo:

cut -d '_' -f 2

Pasar el primer comando al segundo imprimirá las cadenas que le interesan, pero también imprimirá una línea vacía para aquellos casos en los que no hay ningún carácter entre los guiones bajos ( foo__barpor ejemplo). Puede filtrarlos usando grep .el cual solo imprimirá líneas que contengan al menos un carácter (incluido el espacio en blanco). Finalmente, puedes contar pasando la salida porsortyuniq -c.

Poniéndolo todo junto te da:

$ for i in *_*_*; do echo "$i" | cut -d '_' -f 2 ; done | 
   grep . | sort | uniq -c

  3 ABC
  2 DEF
  1 MNO

Si realmente quieres que el número esté en el otro lado, puedes usar awk:

$ for i in *_*_*; do echo "$i" | cut -d '_' -f 2 ; done | 
   grep . | sort | uniq -c | awk '{print $2,$1}'

ABC 3
DEF 2
MNO 1

Respuesta3

Aquí hay una manera de hacer el trabajo usando Perl.

perl -aE '/^[^_]+_\K[^_]+/ && $h{$&}++}{say$_," ",$h{$_} for sort keys %h' file
ABC 3
DEF 3
MNO 2

Explicación:

perl -aE                # invoque Perl compiler with autosplit lines
/^[^_]+_\K[^_]+/        # match non _ characters after the first _
 &&                     # execute the next command if a match is found
$h{$&}++}               # increment a counter for each match founded
{say$_," ",$h{$_}       # finally print each match and the counter associated
for sort keys %h        # for each sorted matches

información relacionada