¿Cómo puedo obtener el tamaño de un archivo en un script bash?

246

¿Cómo puedo obtener el tamaño de un archivo en un script bash?

¿Cómo asigno esto a una variable bash para poder usarlo más tarde?

embrujado85
fuente
stackoverflow.com/questions/5920333/how-to-check-size-of-a-file LOL para la migración :-)
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
1
Empareje esto con pvy catpara un comando de copia que muestre progreso y ETA :)
sudo
stat -c% s file.name
neverMind9

Respuestas:

242

Su mejor apuesta si está en un sistema GNU:

stat --printf="%s" file.any

De man stat :

% s tamaño total, en bytes

En un script bash:

#!/bin/bash
FILENAME=/home/heiko/dummy/packages.txt
FILESIZE=$(stat -c%s "$FILENAME")
echo "Size of $FILENAME = $FILESIZE bytes."

NOTA: vea la respuesta de @ chbrown para saber cómo usar stat en la terminal en Mac OS X.

b01
fuente
77
@ haunted85 states la forma más sencilla, suponiendo que esté utilizando Linux o Cygwin ( statno es estándar). wc -csegún lo sugerido por Eugéne es portátil.
Gilles
2
stat: illegal option -- c
Iulian Onofrei
stat --printf="%s" file.txtno muestra nada en Debian Jessie ...
woohoo
55
En MacOS esto funciona:stat -f%z myfile.tar
ccpizza
2
@woohoo Su solicitud sobrescribe la salida. man statdice que --printf omite la nueva línea final. Use --formato -cpara ver la salida. Obtenga más información al comparar stat --printf="%s" file.any | xxd -constat -c "%s" file.any | xxd -
nieto
92
file_size_kb=`du -k "$filename" | cut -f1`

El problema con el uso states que es una extensión GNU (Linux). du -ky cut -f1están especificados por POSIX y, por lo tanto, son portátiles para cualquier sistema Unix.

Solaris, por ejemplo, se envía con bash pero no con stat. Entonces esto no es del todo hipotético.

lstiene un problema similar en que no se especifica el formato exacto de la salida, por lo que el análisis de su salida no se puede hacer de forma portátil. du -hTambién es una extensión GNU.

Apéguese a construcciones portátiles siempre que sea posible, y facilitará la vida de alguien en el futuro. Quizás el tuyo.

Nemo
fuente
48
duno da el tamaño del archivo, da una indicación de cuánto espacio usa el archivo, que es sutilmente diferente (por lo general, el tamaño reportado dues el tamaño del archivo redondeado al número más cercano de bloques, donde un bloque es típicamente 512B o 1kB o 4kB).
Gilles
77
@Gilles, los archivos dispersos (es decir, los que tienen agujeros) reportan menos de la longitud.
vonbrand
55
Esta, con --byteso en -blugar de -k, debería ser la respuesta aceptada.
Amedee Van Gasse
1
La -hopción ("humano")du producirá la respuesta más apropiada para casos generales: file_size=`du -h "$filename" | cut -f1ya que mostrará K (kilobytes), M (Megabytes) o G (Gigabytes) según corresponda.
Fralau 01 de
1
@fralau: El OP quiere "asignar esto a una variable bash para que puedan usarlo más tarde", por lo que es mucho más probable que quieran un valor numérico real, no una aproximación legible por humanos. Además, -hes una extensión GNU; no es estándar
Nemo
74

También puede usar el comando "Word Count" ( wc):

wc -c "$filename" | awk '{print $1}'

El problema con wces que agregará el nombre del archivo y sangrará la salida. Por ejemplo:

$ wc -c somefile.txt
    1160 somefile.txt

Si desea evitar encadenar un lenguaje interpretado completo o un editor de secuencias solo para obtener un recuento de tamaño de archivo, simplemente redirija la entrada del archivo para que wcnunca vea el nombre de archivo:

wc -c < "$filename"

Esta última forma se puede usar con la sustitución de comandos para obtener fácilmente el valor que estaba buscando como una variable de shell, como lo menciona Gilles a continuación.

size="$(wc -c <"$filename")"
Eugenio
fuente
30
wc -c <"$FILENAME"da el tamaño sin otra migaja, por lo tanto size=$(wc -c <"$FILENAME").
Gilles
66
Solo un punto más: acabo de probarlo y wc -c < fileparece ser muy rápido, al menos en OS X. Supongo que wc tiene el cerebro para tratar de registrar el archivo si solo se especifica -c.
Edward Falk
44
@EdwardFalk: GNU wc -cusa fstat, pero luego busca el penúltimo bloque del archivo y lee los últimos st_blksizebytes hasta . Aparentemente, esto se debe a que los archivos en Linux /procy, /syspor ejemplo, tienen tamaños de estadísticas que son solo aproximados y wcquieren informar el tamaño real, no el tamaño de estadísticas. Supongo que sería extraño wc -cinformar un tamaño diferente wc, pero no es idea leer datos del archivo si es un archivo de disco normal y no está en la memoria. O peor, almacenamiento de cinta casi en línea ...
Peter Cordes
1
Parece que printftodavía ve la sangría, por ejemplo, printf "Size: $size"-> size: <4 spaces> 54339. Por otro lado echoignora los espacios en blanco. ¿Alguna forma de hacerlo consistente?
Eugene Kulabuhov
2
@keithpjolley: llamando fstat. Intenta correr strace wc -c </etc/passwdy podrás ver lo que está haciendo.
Nemo
48

Los BSD (Mac OS X) stattienen un indicador de argumento de formato diferente y diferentes especificadores de campo. De man stat(1):

  • -f format: Muestra información utilizando el formato especificado. Consulte la sección FORMATOS para obtener una descripción de los formatos válidos.
  • ... la sección FORMATOS ...
  • z: El tamaño del archivo en bytes.

Así que todos juntos ahora:

stat -f%z myfile1.txt
marrón
fuente
28

Depende de lo que entiendas por tamaño .

size=$(wc -c < "$file")

le dará la cantidad de bytes que se pueden leer del archivo. IOW, es el tamaño del contenido del archivo. Sin embargo, leerá el contenido del archivo (excepto si el archivo es un archivo normal o un enlace simbólico a un archivo normal en la mayoría de las wcimplementaciones como una optimización). Eso puede tener efectos secundarios. Por ejemplo, para una tubería con nombre, lo que se ha leído ya no se puede leer nuevamente y para cosas como /dev/zeroo /dev/randomque son de tamaño infinito, llevará un tiempo. Eso también significa que necesita readpermiso para el archivo, y la última marca de tiempo de acceso del archivo puede actualizarse.

Eso es estándar y portátil, sin embargo, tenga en cuenta que algunas wcimplementaciones pueden incluir espacios en blanco iniciales en esa salida. Una forma de deshacerse de ellos es usar:

size=$(($(wc -c < "$file")))

o para evitar un error sobre una expresión aritmética vacía en dasho yashcuando wcno produce salida (como cuando el archivo no se puede abrir):

size=$(($(wc -c < "$file") +0))

ksh93tiene wcincorporado (siempre que lo habilite, también puede invocarlo como command /opt/ast/bin/wc) lo que lo convierte en el más eficiente para los archivos normales en ese shell.

Varios sistemas tienen un comando llamado statque es una interfaz para los stat()o lstat()llamadas al sistema.

Esos reportan información encontrada en el inodo. Una de esa información es el st_sizeatributo. Para los archivos normales, ese es el tamaño del contenido (cuántos datos podrían leerse en ausencia de error (eso es lo que la mayoría de las wc -cimplementaciones usan en su optimización)). Para enlaces simbólicos, ese es el tamaño en bytes de la ruta de destino. Para canalizaciones con nombre, según el sistema, es 0 o el número de bytes actualmente en el búfer de canalización. Lo mismo para dispositivos de bloque donde, dependiendo del sistema, obtienes 0 o el tamaño en bytes del almacenamiento subyacente.

No necesita permiso de lectura en el archivo para obtener esa información, solo busque permiso para el directorio al que está vinculado.

Por orden cronológico, hay:

  • IRIXstat (años 90):

    stat -qLs -- "$file"

    devuelve el st_sizeatributo de $file( lstat()) o:

    stat -s -- "$file"

    igual excepto cuando $filees un enlace simbólico en cuyo caso es el st_sizedel archivo después de la resolución del enlace simbólico.

  • zsh statincorporado (ahora también conocido como zstat) en el zsh/statmódulo (cargado con zmodload zsh/stat) (1997):

    stat -L +size -- $file # st_size of file
    stat +size -- $file    # after symlink resolution

    o para almacenar en una variable:

    stat -L -A size +size -- $file

    obviamente, ese es el más eficiente en ese shell.

  • GNUstat (2001); También en BusyBox statdesde 2005 (copiado de GNU stat):

    stat -c %s -- "$file"  # st_size of file
    stat -Lc %s -- "$file" # after symlink resolution

    (tenga en cuenta que el significado de -Lse invierte en comparación con IRIX o zsh stat.

  • BSDstat (2002):

    stat -f %z -- "$file"  # st_size of file
    stat -Lf %z -- "$file" # after symlink resolution

O puede usar la función stat()/ lstat()de algún lenguaje de script como perl:

perl -le 'print((lstat shift)[7])' -- "$file"

AIX también tiene un istatcomando que volcará toda la información stat()(no lstat(), así que no funcionará en enlaces simbólicos) y con la que podría procesar posteriormente, por ejemplo:

LC_ALL=C istat "$file" | awk 'NR == 4 {print $5}'

(Gracias a @JeffSchaller por la ayuda para descubrir los detalles ).

En tcsh:

@ size = -Z $file:q

(tamaño después de la resolución del enlace simbólico)

Mucho antes de que GNU introdujera su statcomando, lo mismo podría lograrse con el findcomando GNU con su -printfpredicado (ya en 1991):

find -- "$file" -prune -printf '%s\n'    # st_size of file
find -L -- "$file" -prune -printf '%s\n' # after symlink resolution

Sin embargo, un problema es que no funciona si $filecomienza con -o es un findpredicado (como !, (...).

El comando estándar para obtener la información stat()/ lstat()es ls.

POSIXY, puedes hacer:

LC_ALL=C ls -dn -- "$file" | awk '{print $5; exit}'

y agregue -Llo mismo después de la resolución del enlace simbólico. Eso no funciona para los archivos de dispositivos, aunque en la 5 ª campo es el dispositivo de mayor número en lugar del tamaño.

Para los dispositivos de bloque, los sistemas donde stat()devuelve 0 st_size, generalmente tienen otras API para informar el tamaño del dispositivo de bloque. Por ejemplo, Linux tiene BLKGETSIZE64 ioctl(), y la mayoría de las distribuciones de Linux ahora se envían con un blockdevcomando que puede usarlo:

blockdev --getsize64 -- "$device_file"

Sin embargo, necesita permiso de lectura en el archivo del dispositivo para eso. Por lo general, es posible derivar el tamaño por otros medios. Por ejemplo (todavía en Linux):

lsblk -bdno size -- "$device_file"

Debería funcionar excepto para dispositivos vacíos.

Un enfoque que funciona para todos los archivos buscables (por lo que incluye archivos normales, la mayoría de los dispositivos de bloque y algunos dispositivos de caracteres) es abrir el archivo y buscar hasta el final:

  • Con zsh(después de cargar el zsh/systemmódulo):

    {sysseek -w end 0 && size=$((systell(0)))} < $file
  • Con ksh93:

    < "$file" <#((size=EOF))

    o

    { size=$(<#((EOF))); } < "$file"
  • con perl:

    perl -le 'seek STDIN, 0, 2 or die "seek: $!"; print tell STDIN' < "$file"

Para las tuberías con nombre, hemos visto que algunos sistemas (AIX, Solaris, HP / UX al menos) hacen que la cantidad de datos en el búfer de tuberías esté disponible en stat()'s st_size. Algunos (como Linux o FreeBSD) no lo hacen.

Al menos en Linux, puede usar FIONREAD ioctl()después de haber abierto la tubería (en modo lectura + escritura para evitar que se cuelgue):

fuser -s -- "$fifo_file" && 
  perl -le 'require "sys/ioctl.ph";
            ioctl(STDIN, &FIONREAD, $n) or die$!;
            print unpack "L", $n' <> "$fifo_file"

Sin embargo, tenga en cuenta que si bien no lee el contenido de la tubería, la simple apertura de la tubería con nombre aquí todavía puede tener efectos secundarios. Estamos usando fuserpara verificar primero que algún proceso ya tiene la tubería abierta para aliviar eso, pero eso no es infalible ya que es fuserposible que no pueda verificar todos los procesos.

Ahora, hasta ahora solo hemos estado considerando el tamaño de los datos primarios asociados con los archivos. Eso no tiene en cuenta el tamaño de los metadatos y toda la infraestructura de soporte necesaria para almacenar ese archivo.

Otro atributo de inodo devuelto por stat()es st_blocks. Esa es la cantidad de bloques de 512 bytes que se utilizan para almacenar los datos del archivo (y, a veces, algunos de sus metadatos, como los atributos extendidos en los sistemas de archivos ext4 en Linux). Eso no incluye el inodo en sí, o las entradas en los directorios a los que está vinculado el archivo.

El tamaño y el uso del disco no están necesariamente estrechamente relacionados como la compresión, la escasez (a veces algunos metadatos), la infraestructura adicional como los bloques indirectos en algunos sistemas de archivos influyen en estos últimos.

Eso suele ser lo que se duusa para informar el uso del disco. La mayoría de los comandos enumerados anteriormente podrán obtener esa información.

  • POSIXLY_CORRECT=1 ls -sd -- "$file" | awk '{print $1; exit}'
  • POSIXLY_CORRECT=1 du -s -- "$file" (no para directorios donde eso incluiría el uso del disco de los archivos dentro).
  • ÑU find -- "$file" -printf '%b\n'
  • zstat -L +block -- $file
  • ÑU stat -c %b -- "$file"
  • BSD stat -f %b -- "$file"
  • perl -le 'print((lstat shift)[12])' -- "$file"
Stéphane Chazelas
fuente
claramente la respuesta más completa e informativa. gracias. puedo usar esto para crear scripts de bash multiplataforma usando la información de estadísticas BSD y GNU
oligofren
1
Dato curioso: GNU coreutils wc -cusa fstat, pero luego lee los últimos st_blksizebytes. Aparentemente, esto se debe a que los archivos en Linux /procy, /syspor ejemplo, tienen tamaños de estadísticas que son solo aproximados . Esto es bueno para la corrección, pero malo si el final del archivo está en el disco y no en la memoria (especialmente si se usa en muchos archivos en un bucle). Y muy malo si el archivo se migra a un almacenamiento de cinta cercano a la línea o, por ejemplo, a un sistema de archivos de descompresión transparente FUSE.
Peter Cordes
¿No funcionaría esto tambiénls -go file | awk '{print $3}'
Steven Penny
@StevenPenny esos -goserían los SysV , no funcionarían en BSD (opcional (XSI) en POSIX). También necesitaría ls -god file | awk '{print $3; exit}'( -dpara que funcione en directorios, exitpara enlaces simbólicos con nuevas líneas en el destino). Los problemas con los archivos del dispositivo también permanecen.
Stéphane Chazelas
1
@ αғsнιη la API de Unix no hace distinción entre archivos de texto y binarios. Son todas las secuencias de bytes. Algunas aplicaciones pueden querer interpretar esos bytes como texto, pero obviamente no lo wc -cque informa el número de bytes.
Stéphane Chazelas
22

Este script combina muchas formas de calcular el tamaño del archivo:

(
  du --apparent-size --block-size=1 "$file" 2>/dev/null ||
  gdu --apparent-size --block-size=1 "$file" 2>/dev/null ||
  find "$file" -printf "%s" 2>/dev/null ||
  gfind "$file" -printf "%s" 2>/dev/null ||
  stat --printf="%s" "$file" 2>/dev/null ||
  stat -f%z "$file" 2>/dev/null ||
  wc -c <"$file" 2>/dev/null
) | awk '{print $1}'

El script funciona en muchos sistemas Unix, incluidos Linux, BSD, OSX, Solaris, SunOS, etc.

El tamaño del archivo muestra el número de bytes. Es el tamaño aparente, que son los bytes que utiliza el archivo en un disco típico, sin compresión especial, o áreas dispersas especiales, o bloques no asignados, etc.

Este script tiene una versión de producción con más ayuda y más opciones aquí: https://github.com/SixArm/file-size

joelparkerhenderson
fuente
9

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
8

ls -l filename le dará mucha información sobre un archivo, incluido su tamaño, permisos y propietario.

El tamaño del archivo en la quinta columna, y se muestra en bytes. En el ejemplo a continuación, el tamaño del archivo es de menos de 2 KB:

-rw-r--r-- 1 user owner 1985 2011-07-12 16:48 index.php

Editar: aparentemente no es tan confiable como el statcomando.

Druckles
fuente
Creo que ambos ls -ly el statcomando dan información confiable sobre el tamaño. No encontré ninguna referencia a lo contrario. ls -sdará tamaño en número de bloques.
dabest1
2
@ dabest1 no es confiable en el sentido de que en otro Unix, su salida puede ser diferente (y en algunos Unix lo es).
Eugene Bujak
Sí, IIRC, Solaris no mostraba el nombre del grupo de forma predeterminada, lo que generaba menos columnas en la salida.
Edward Falk
Dado que el tamaño es numérico puro, rodeado de espacios en blanco, y el año de la fecha es numérico puro, en un formato definido, sería posible utilizar una expresión regular para tratar usuario + propietario como un campo, independientemente de si el grupo estaba presente o no. (¡un ejercicio para el lector!)
MikeW
5

du filename le dirá el uso del disco en bytes.

Prefiero du -h filename, que te da el tamaño en un formato legible para humanos.

Osito de peluche
fuente
2
that or stat -c "%s";)
1
Este sabor de duimprime el tamaño en bloques de 1024 bytes, no un simple recuento de bytes.
Peter Lyons
Tenga en cuenta que el estándar duproporciona una salida en número de unidades de 512 bytes. GNU duusa kibibytes a menos que se llame con POSIXLY_CORRECTen su entorno.
Stéphane Chazelas
1
Para archivos de tipo directorio , eso proporciona el uso del disco del directorio, pero también de todos los demás archivos dentro (recursivamente).
Stéphane Chazelas
3

Cree pequeñas funciones de utilidad en sus scripts de shell en las que pueda delegar.

Ejemplo

#! /bin/sh -
# vim: set ft=sh

# size utility that works on GNU and BSD systems
size(){
    case $(uname) in
        (Darwin | *BSD*)
            stat -Lf %z -- "$1";;
        (*) stat -c %s -- "$1"
    esac
}

for f do
    printf '%s\n' "$f : $(gzip < "$f" | wc -c) bytes (versus $(size "$f") bytes)"
done

Basado en información de la respuesta de @ Stéphane Chazelas.

oligofren
fuente
Consulte también gzip -v < file > /dev/nullpara verificar la compresibilidad de un archivo.
Stéphane Chazelas
@ StéphaneChazelas no estoy seguro si creo que fue una mejora. esas declaraciones de casos pueden posponer fácilmente los noobs; Ciertamente, nunca recuerdo cómo hacerlo correctamente :-) ¿son las declaraciones de casos inherentemente más portátiles desde que lo hiciste? veo el punto cuando hay más de dos casos, pero de lo contrario ... +
oligofren
1
Supongo que también es cuestión de gustos, pero aquí es el caso típico en el que querrías usar una casedeclaración. casees la construcción Bourne / POSIX para hacer coincidencia de patrones. [[...]]es solo ksh / bash / zsh (con variaciones).
Stéphane Chazelas
2

Encontré un forro AWK 1, y tenía un error, pero lo arreglé. También agregué en PetaBytes después de TeraBytes.

FILE_SIZE=234234 # FILESIZE IN BYTES
FILE_SIZE=$(echo "${FILE_SIZE}" | awk '{ split( "B KB MB GB TB PB" , v ); s=1; while( $1>1024 ){ $1/=1024; s++ } printf "%.2f %s", $1, v[s] }')

Teniendo en cuenta que stat no está en todos los sistemas, casi siempre puede usar la solución AWK. Ejemplo; la Raspberry Pi no tiene estadísticas, pero sí tiene awk .

findrbot_admin
fuente
1
Completamente NO lo que pidió el OP, pero es un buen trabajo.
Gypsy Spellweaver
0

Otra forma compatible con POSIX sería usar awkcon su length()función que devuelve la longitud, en caracteres en cada línea del archivo de entrada, excluyendo los caracteres de nueva línea. Entonces haciendo

awk '{ sum+=length } END { print sum+NR }' file

nos aseguramos de que NRse agregue sum, lo que da como resultado el recuento total de caracteres y el número total de nuevas líneas encontradas en el archivo. La length()función en awktoma un argumento que por defecto significa length($0)que es para la línea completa actual.

Inian
fuente
No si la última línea no termina en una nueva línea: printf 'a\nb' | awk '{ sum+=length } END { print sum+NR }'debería imprimir 3 pero imprime 4.
Isaac
-1

Me gusta la opción wc yo mismo. Junto con 'bc', puede obtener decimales en tantos lugares como desee.

Estaba buscando mejorar un script que tenía que despertaba la columna 'tamaño de archivo' de un comando 'ls -alh'. No quería solo los tamaños de archivos enteros, y dos decimales parecían adaptarse, así que después de leer esta discusión, se me ocurrió el código a continuación.

Sugiero romper la línea en punto y coma si incluye esto en un script.

file=$1; string=$(wc -c $file); bite=${string% *}; okay=$(echo "scale=2; $bite/1024" | bc);friend=$(echo -e "$file $okay" "kb"); echo -e "$friend"

Mi script se llama gpfl , para "obtener la longitud del archivo de imagen". Lo uso después de hacer un mogrify en un archivo en imagemagick, antes de abrir o volver a cargar una imagen en un visor jpeg GUI.

No sé cómo esto califica como una "respuesta", ya que toma mucho prestado de lo que ya se ha ofrecido y discutido. Entonces lo dejaré allí.

BZT

BZT
fuente
1
Preferiría usar "stat" o "ls". Por lo general, no me gusta usar "wc" para obtener tamaños de archivo porque lee físicamente todo el archivo. Si tiene muchos archivos, o archivos particularmente grandes, esto puede llevar mucho tiempo. Pero tu solución es creativa ... + 1.
Kevin Fegan
2
Estoy de acuerdo con la idea de usar "stat" sobre "wc" para el tamaño del archivo, sin embargo, si usa "wc -c", no se leerán datos; en su lugar, lseek se usará para calcular la cantidad de bytes en un archivo. lingrok.org/xref/coreutils/src/wc.c#228
bbaja42
1
@ bbaja42: tenga en cuenta que GNU Coreutils wclee el último bloque del archivo, en caso de que stat.st_sizefuera solo una aproximación (como para Linux /procy /sysarchivos). Supongo que decidieron no hacer el comentario principal más complicado cuando agregaron esa lógica un par de líneas: lingrok.org/xref/coreutils/src/wc.c#246
Peter Cordes
-1

El método más rápido y simple (IMO) es:

bash_var=$(stat -c %s /path/to/filename)
WinEunuuchs2Unix
fuente
2
Luego vota una o más de las respuestas existentes que mencionan stat; no es necesario repetirlo de nuevo ...
Jeff Schaller
1
@JeffSchaller Acabo de votar la respuesta de Stephane sobre tus instrucciones. Creo que es demasiado complicado para mis propósitos. Es por eso que publiqué esta respuesta simple para almas afines.
WinEunuuchs2Unix
1
Gracias; es solo que una sexta instancia de una respuesta "estadística" no simplifica estas preguntas y respuestas, sino que prefiere que un nuevo lector se pregunte "¿en qué se diferencia esta respuesta de las otras?" y conducir a más confusión en lugar de menos.
Jeff Schaller
@JeffSchaller, supongo. Pero podría quejarme de las muchas duy wcrespuestas que deberían tener un descargo de responsabilidad NUNCA HAGA ESTO en la vida real. Esta noche utilicé mi respuesta en una aplicación de la vida real y pensé que valía la pena compartirla. Supongo que todos tenemos nuestras opiniones encogidas de hombros .
WinEunuuchs2Unix