Использование awk и просмотр файлов в каталоге

В системе с установленной командой GNU stat (как и в любом стандартном дистрибутиве Linux) вы можете получить тип fs для данного файла, не требуя любой синтаксический анализ с использованием команды stat :

stat -f -c %T filename

-f указывает stat предоставить информацию о файловой системе вместо файла, и -c% T устанавливает выходной формат, включающий только тип файловой системы, удобочитаемый человеком (% T ).

Таким образом, вы можете использовать это (в bash) как:

if [[ $(stat -f -c %T filename) == ext4 ]]; then
  # ext4 specific command
fi

man stat предоставит дополнительную информацию.

2
25.02.2018, 01:46
4 ответа

Con algunas mejoras a su secuencia de comandos,

#!/bin/bash
cd "$1" || { printf 'unable to navigate to target\n' >&2; exit 1 ; }
for file in *.dat; do
    test -f "$file" || continue
    awk 'count+=sub(/<Overall>/, ""){sum+=$0}END{print (count)?(sum/count):0}}' "$file"
done
  1. Dado que ya estácd-ing a "$1", no necesita for file in "$1", pero simplemente recorra las extensiones de archivo necesariasfor file in *.dat
  2. La condición test -f "$file" || continuese asegurará de que si no hay archivos en la ruta que se está examinando, se produzca una salida ordenada del bucle for -en lugar de pasar un globo no expandido a awkpara procesar
  3. Pase el nombre del archivo como $fileen lugar de una cadena literal file. Las variables de shell deben tener el prefijo $antes del nombre y, por lo general, deben estar entre comillas dobles -.
  4. Una mejora menor en la cláusula ENDde awkpara comprobar si el recuento no es -cero antes de dividirlo.
3
27.01.2020, 21:52

for file in "$1"ejecutará el bucle exactamente una vez, con fileestablecido en el valor literal del primer argumento del script. Dado que se cita "$1", los comodines dentro no se expanden. Si pasa un directorio al script, también pasará el nombre del directorio a awk, y es probable que no le guste mucho, mi gawkdice:

gawk: warning: command line argument `/tmp/test/' is a directory: skipped

Si desea ejecutar el ciclo sobre cada archivo individualmente, use un comodín en el lugar adecuado. El *aquí se expandirá a los nombres de archivo en el directorio actual, el que se da como argumento ya que acabamos de hacer un cdallí:

#!/bin/sh
cd "$1" || exit 1 
for file in * ; do
    awk '...' "$file"
done

Alternativamente, puede pasar una lista de nombres de archivo como argumento al script y luego recorrerlos:

#!/bin/sh
for file in "$@" ; do
    awk '...' "$file"
done

En la práctica, haría myscript /some/path/hotel*.daty dejaría que el shell expandiera los nombres de los archivos a la línea de comandos de los scripts. "$@"se expande a la lista de argumentos de línea de comando.


Dicho esto, el guión awktambién está un poco fuera de lugar. Tal como lo escribiste, la condición de la primera regla es count+=sub(/<Overall>/, ""). Eso es cierto siempre que countsea distinto de cero después de la suma, independientemente de lo que sub()devuelva esta vez. Esto significa que la regla {sum+=$0}se ejecuta cada vez que <Overall>se ve al menos una vez. Sumará sin aumentar count.

Probablemente querrás algo como esto:

awk '/^<Overall>/ {sub(/<Overall>/, ""); count += 1; sum += $0} END {print sum/count}' "$file"

Para mostrar el nombre del archivo, puede echo:

#!/bin/sh
cd "$1" || exit 1 
for file in * ; do
    printf "%s " "$file"
    awk '/^<Overall>/ {sub(/<Overall>/, ""); count += 1; sum += $0} END {print sum/count}' "$file"
done
1
27.01.2020, 21:52

Con un soloawkguión (sin forbucle y múltiples awkinvocaciones):

Archivos de entrada de muestra:

$ head reviews_folder/hotel_*.dat
==> reviews_folder/hotel_111.dat <==
<Overall>1
<Overall>4
<Overall>3

==> reviews_folder/hotel_222.dat <==
<Overall>11
<Overall>5
<Overall>7

==> reviews_folder/hotel_333.dat <==
<Overall>7
<Overall>4
<Overall>10

awk -F'>' 'fn && FILENAME != fn{ 
              sub(".*/", "", fn);
              print fn, sprintf("%.2f", sum/n); sum = 0
          }
          { sum += $2; n = FNR; fn = FILENAME }
          END{ 
              sub(".*/", "", fn);
              print fn, sprintf("%.2f", sum/n)
          }' reviews_folder/hotel_*.dat

La salida:

hotel_111.dat 2.67
hotel_222.dat 7.67
hotel_333.dat 7.00
5
27.01.2020, 21:52

Use el siguiente comando contra cada archivo. Obtendrá el promedio. Probado y funcionado bien

Entrada

<Overall>1
<Overall>4
<Overall>3

i=`awk '{print NR}' hotel_111.dat| tail -1 `

awk -F ">" -v i="$i" 'BEGIN{sum=0} {sum=sum+$2} END{print FILENAME;print  sum/i}' hotel_111.dat  | sed "N;s/\n/ /g"

salida

hotel_111.dat 2.66667
0
27.01.2020, 21:52

Теги

Похожие вопросы