¿Cómo verificar el tamaño de un archivo usando Bash?

145

Tengo un script que verifica el tamaño 0, pero pensé que debe haber una forma más fácil de verificar el tamaño de los archivos. Es decir, file.txtnormalmente es 100k; cómo hacer que un script verifique si es inferior a 90k (incluido 0), y que haga una nueva copia porque el archivo está dañado en este caso.

Lo que estoy usando actualmente ...

if [ -n file.txt ]
then
 echo "everything is good"
else
 mail -s "file.txt size is zero, please fix. " myemail@gmail.com < /dev/null
 # Grab wget as a fallback 
 wget -c https://www.server.org/file.txt -P /root/tmp --output-document=/root/tmp/file.txt
 mv -f /root/tmp/file.txt /var/www/file.txt
fi
usuario349418
fuente
1
unix.stackexchange.com/questions/16640/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Respuestas:

250

[ -n file.txt ]no verifica su tamaño, verifica que la cadena file.txtno sea de longitud cero, por lo que siempre tendrá éxito.

Si quiere decir "el tamaño no es cero", necesita [ -s file.txt ].

Para obtener el tamaño de un archivo, puede usar wc -cpara obtener el tamaño (longitud del archivo) en bytes:

file=file.txt
minimumsize=90000
actualsize=$(wc -c <"$file")
if [ $actualsize -ge $minimumsize ]; then
    echo size is over $minimumsize bytes
else
    echo size is under $minimumsize bytes
fi

En este caso, parece que eso es lo que quieres.

Pero para su información, si desea saber cuánto espacio de disco está usando el archivo, puede usar du -kpara obtener el tamaño (espacio de disco usado) en kilobytes:

file=file.txt
minimumsize=90
actualsize=$(du -k "$file" | cut -f 1)
if [ $actualsize -ge $minimumsize ]; then
    echo size is over $minimumsize kilobytes
else
    echo size is under $minimumsize kilobytes
fi

Si necesita más control sobre el formato de salida, también puede mirar stat. En Linux, comenzaría con algo como stat -c '%s' file.txt, y en BSD / Mac OS X, algo así stat -f '%z' file.txt.

Mikel
fuente
55
¿Por qué en du -b "$file" | cut -f 1lugar de stat -c '%s' "$file"? O stat --printf="%s" "$file"?
mivk
1
Solo porque es más portátil. BSD y Linux stat tienen diferentes banderas.
Mikel
1
Tuve que modificarlo ... | cut -d' ' -f1para que funcione en Ubuntu.
Mikepote
8
Use wc -c < "$file"(tenga en cuenta la <), en cuyo caso no necesita la | cut ...parte (que, según lo publicado, no funciona en OSX). El BLOCKSIZEvalor mínimo para duen OSX es 512.
mklement0
3
@PetriSirkkala En mi sistema Linux, ¿ wc -c <filenametambién usa fstaty seek? Tenga en cuenta que fstattoma un fd, no un nombre de ruta.
Mikel
24

Me sorprende que nadie mencione statverificar el tamaño del archivo. Algunos métodos son definitivamente mejores: usar -spara averiguar si el archivo está vacío o no es más fácil que cualquier otra cosa, si eso es todo lo que desea. Y si desea encontrar archivos de un tamaño, entonces findsin duda es el camino a seguir.

También me gusta dumucho obtener el tamaño del archivo en kb, pero, para bytes, usaría stat:

size=$(stat -f%z $filename) # BSD stat

size=$(stat -c%s $filename) # GNU stat?
Daniel C. Sobral
fuente
2
states una gran idea, pero en CentOS esto es lo que funcionó para mí:size=$(stat -c%s $filename)
Oz Solomon
2
La diferencia entre GNU y BSD es lo que, desafortunadamente, hace que esta alternativa sea un poco menos atractiva. :(
lapo
1
stat puede ser engañoso si el archivo es escaso. Puede usar los bloques informados por stat para calcular el espacio utilizado.
Ajith Antony
@AjithAntony Ese es un punto interesante que no se me ocurrió. Puedo ver statlo correcto en algunas situaciones, y los archivos dispersos no son relevantes en la mayoría de las situaciones, aunque ciertamente no en todos.
Daniel C. Sobral
17

Solución alternativa con awk y paréntesis doble:

FILENAME=file.txt
SIZE=$(du -sb $FILENAME | awk '{ print $1 }')

if ((SIZE<90000)) ; then 
    echo "less"; 
else 
    echo "not less"; 
fi
fstab
fuente
1
Agradable, pero no funcionará en OSX, donde duno es compatible -b. (Puede ser una elección de estilo consciente, pero sólo por mencionar la alternativa: se puede omitir el $interior prefijo (( ... ))al hacer referencia a las variables: ((SIZE<90000)))
mklement0
1
En realidad, fue una edición de un usuario anterior que pensó que estaba mal omitir el$
fstab
2
@fstab, puede omitir awkusando read( bashcomando interno):read SIZE _ <<<$(du -sb "$FILENAME")
Jdamian
13

Si findmaneja esta sintaxis, puede usarla:

find -maxdepth 1 -name "file.txt" -size -90k

Esto dará salida file.txta stdout si y solo si el tamaño file.txtes menor a 90k. Para ejecutar un script scriptsi file.txttiene un tamaño inferior a 90k:

find -maxdepth 1 -name "file.txt" -size -90k -exec script \;
gniourf_gniourf
fuente
3
+1, pero también para que funcione en OSX, necesita un argumento de directorio de destino explícito, por ejemplo:find . -maxdepth 1 -name "file.txt" -size -90k
mklement0
8

Si está buscando solo el tamaño de un archivo:

$ cat $file | wc -c
> 203233
BananaNeil
fuente
1
Esta podría ser la respuesta viable más corta, pero probablemente también sea la más lenta. :)
SunSparc
2
Sí, pero ciertamente económicamente superior: costo del tiempo de ingeniería> costo del tiempo de cálculo
BananaNeil
8
wc -c "$file"fue dada como respuesta en 2011 (hace tres años). Sí, wc -c "$file"tiene el problema de que genera el nombre del archivo y el recuento de caracteres, por lo que las primeras respuestas agregaron un comando para separar el recuento. Pero wc -c < "$file", que soluciona ese problema, se agregó como un comentario en mayo de 2014. Su respuesta es equivalente a eso, excepto que agrega un "uso inútil de cat" . Además, debe citar todas las referencias de variables de shell a menos que tenga una buena razón para no hacerlo.
G-Man dice 'Restablecer a Monica' el
1
Puede hacerlo más eficiente utilizando head -c en lugar de cat.if [$ (head -c 90000 $ file | wc -c) -lt 90000]; entonces echo "El archivo es más pequeño que 90k"; fi. Probado en CentOS, por lo que puede o no funcionar en BSD u OSX.
Kevin Keane
@BananaNeil, ¿cómo hacer este proceso cada 20 segundos para poder verificar el incremento del tamaño del archivo, etc.?
Un Sahra
6

Esto funciona tanto en Linux como en Macos

function filesize
{
    local file=$1
    size=`stat -c%s $file 2>/dev/null` # linux
    if [ $? -eq 0 ]
    then
        echo $size
        return 0
    fi

    eval $(stat -s $file) # macos
    if [ $? -eq 0 ]
    then
        echo $st_size
        return 0
    fi

    return -1
}
Neil McGill
fuente
5

stat parece hacer esto con la menor cantidad de llamadas al sistema:

$ set debian-live-8.2.0-amd64-xfce-desktop.iso

$ strace stat --format %s $1 | wc
    282    2795   27364

$ strace wc --bytes $1 | wc
    307    3063   29091

$ strace du --bytes $1 | wc
    437    4376   41955

$ strace find $1 -printf %s | wc
    604    6061   64793

fuente
Si lo entiendo correctamente, ¿la prueba debería hacerse también con redirección de tubería ?: strace du --bytes $1 2>&1 >/dev/null | wc Si ese es el caso, entonces en la arquitectura amd64 en ArchLinux (generalmente las últimas versiones de todo) tengo 45 líneas para du, 46 líneas para stat, 47 líneas para wcy 72 líneas para find.
VasiliNovikov
5
python -c 'import os; print (os.path.getsize("... filename ..."))'

portátil, todos los sabores de python, evita la variación en dialectos de estadísticas

usuario6336835
fuente
4

Para obtener el tamaño de archivo en Linux y Mac OS X (y presumiblemente en otros BSD), no hay muchas opciones, y la mayoría de las sugeridas aquí solo funcionarán en un sistema.

Teniendo en cuenta f=/path/to/your/file,

¿Qué funciona en Linux y Mac 's Bash?

size=$( perl -e 'print -s shift' "$f" )

o

size=$( wc -c "$f" | awk '{print $1}' )

Las otras respuestas funcionan bien en Linux, pero no en Mac:

  • duno tiene una -bopción en Mac, y el truco BLOCKSIZE = 1 no funciona ("el tamaño mínimo de bloque es 512", lo que conduce a un resultado incorrecto)

  • cut -d' ' -f1 no funciona porque en Mac, el número puede estar alineado a la derecha, rellenado con espacios al frente.

Así que si usted necesita algo flexibles, o es perl's -soperador o wc -cverter al awk '{print $1}'(awk ignorará el espacio en blanco al principio).

Y, por supuesto, con respecto al resto de su pregunta original, use el operador -lt(o -gt):

if [ $size -lt $your_wanted_size ]; then etc.

mivk
fuente
3
+1; si sabe que solo usará el tamaño en un contexto aritmético (donde se ignora el espacio en blanco inicial), puede simplificarlo size=$(wc -c < "$f")(tenga en cuenta <que, lo que hace wcque solo se informe un número). Re comparación: no olvides los más "bash-ful" if (( size < your_wanted_size )); then ...(y también [[ $size -lt $your_wanted_size ]]).
mklement0
3

Según la respuesta de gniourf_gniourf,

find "file.txt" -size -90k

escribirá file.txten stdout si y solo si el tamaño file.txtes menor a 90K, y

encuentre "file.txt" -size -90k -exec command \;

ejecutará el comando commandsi file.txttiene un tamaño inferior a 90K. He probado esto en Linux. De find(1),

... argumentos de línea de comandos siguientes (las -H, -Ly -Popciones) se considera que son nombres de archivos o directorios para ser examinado, hasta el primer argumento que comienza con '-', ...

(énfasis añadido).

G-Man dice 'restablecer a Mónica'
fuente
1
ls -l $file | awk '{print $6}'

asumiendo que el comando ls informa el tamaño del archivo en la columna # 6

yeugeniuss
fuente
1

Me gustaría utilizar du's --thresholdpara esto. No estoy seguro de si esta opción está disponible en todas las versiones de dupero está implementada en la versión de GNU.

Citando del manual de du (1) :

-t, --threshold=SIZE
       exclude entries smaller than SIZE if positive, or entries greater
       than SIZE if negative

Aquí está mi solución, usando du --threshold=para el caso de uso de OP:

THRESHOLD=90k
if [[ -z "$(du --threshold=${THRESHOLD} file.txt)" ]]; then
    mail -s "file.txt size is below ${THRESHOLD}, please fix. " myemail@gmail.com < /dev/null
    mv -f /root/tmp/file.txt /var/www/file.txt
fi

La ventaja de esto, es que dupuede aceptar un argumento para esa opción en un formato conocido - ya sea humana como en 10K, 10MiBo lo que cada vez que se sienta cómodo - no es necesario para convertir manualmente entre formatos / unidades desde dulas manijas eso.

Como referencia, aquí está la explicación de este SIZEargumento en la página del manual:

The SIZE argument is an integer and optional unit (example: 10K is 
10*1024). Units are K,M,G,T,P,E,Z,Y (powers of 1024) or KB,MB,... (powers
of 1000). Binary prefixes can be used, too: KiB=K, MiB=M, and so on.
Doron Behar
fuente
+1 Excelente opción. Lamentablemente, algunos de nosotros estamos atascados con versiones anteriores duque no lo admiten. La --thresholdopción se agregó en coreutils 8.21, lanzado en 2013 .
Amit Naidu
1

Bien, si estás en una Mac, haz esto: ¡ stat -f %z "/Users/Example/config.log" Eso es!

GarfExiXD
fuente