¿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?
pv
y cat
para un comando de copia que muestre progreso y ETA :)
¿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?
pv
y cat
para un comando de copia que muestre progreso y ETA :)
Respuestas:
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.
stat
es la forma más sencilla, suponiendo que esté utilizando Linux o Cygwin ( stat
no es estándar). wc -c
según lo sugerido por Eugéne es portátil.
stat: illegal option -- c
stat --printf="%s" file.txt
no muestra nada en Debian Jessie ...
stat -f%z myfile.tar
man stat
dice que --printf omite la nueva línea final. Use --format
o -c
para ver la salida. Obtenga más información al comparar stat --printf="%s" file.any | xxd -
constat -c "%s" file.any | xxd -
file_size_kb=`du -k "$filename" | cut -f1`
El problema con el uso stat
es que es una extensión GNU (Linux). du -k
y cut -f1
está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.
ls
tiene 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 -h
Tambié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.
du
no 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 du
es 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).
--bytes
o en -b
lugar de -k
, debería ser la respuesta aceptada.
-h
opción ("humano")du
producirá la respuesta más apropiada para casos generales: file_size=`du -h "$filename" | cut -f1
ya que mostrará K (kilobytes), M (Megabytes) o G (Gigabytes) según corresponda.
También puede usar el comando "Word Count" ( wc
):
wc -c "$filename" | awk '{print $1}'
El problema con wc
es 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 wc
nunca 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")"
wc -c <"$FILENAME"
da el tamaño sin otra migaja, por lo tanto size=$(wc -c <"$FILENAME")
.
wc -c < file
parece 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.
wc -c
usa fstat
, pero luego busca el penúltimo bloque del archivo y lee los últimos st_blksize
bytes hasta . Aparentemente, esto se debe a que los archivos en Linux /proc
y, /sys
por ejemplo, tienen tamaños de estadísticas que son solo aproximados y wc
quieren informar el tamaño real, no el tamaño de estadísticas. Supongo que sería extraño wc -c
informar 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 ...
printf
todavía ve la sangría, por ejemplo, printf "Size: $size"
-> size: <4 spaces> 54339
. Por otro lado echo
ignora los espacios en blanco. ¿Alguna forma de hacerlo consistente?
fstat
. Intenta correr strace wc -c </etc/passwd
y podrás ver lo que está haciendo.
Los BSD (Mac OS X) stat
tienen 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.z
: El tamaño del archivo en bytes.Así que todos juntos ahora:
stat -f%z myfile1.txt
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 wc
implementaciones 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/zero
o /dev/random
que son de tamaño infinito, llevará un tiempo. Eso también significa que necesita read
permiso 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 wc
implementaciones 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 dash
o yash
cuando wc
no produce salida (como cuando el archivo no se puede abrir):
size=$(($(wc -c < "$file") +0))
ksh93
tiene wc
incorporado (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 stat
que 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_size
atributo. 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 -c
implementaciones 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_size
atributo de $file
( lstat()
) o:
stat -s -- "$file"
igual excepto cuando $file
es un enlace simbólico en cuyo caso es el st_size
del archivo después de la resolución del enlace simbólico.
zsh
stat
incorporado (ahora también conocido como zstat
) en el zsh/stat
mó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 stat
desde 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 -L
se 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 istat
comando 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 stat
comando, lo mismo podría lograrse con el find
comando GNU con su -printf
predicado (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 $file
comienza con -
o es un find
predicado (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 -L
lo 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 blockdev
comando 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/system
mó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 fuser
para verificar primero que algún proceso ya tiene la tubería abierta para aliviar eso, pero eso no es infalible ya que es fuser
posible 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 du
usa 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).find -- "$file" -printf '%b\n'
zstat -L +block -- $file
stat -c %b -- "$file"
stat -f %b -- "$file"
perl -le 'print((lstat shift)[12])' -- "$file"
wc -c
usa fstat
, pero luego lee los últimos st_blksize
bytes. Aparentemente, esto se debe a que los archivos en Linux /proc
y, /sys
por 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.
ls -go file | awk '{print $3}'
-go
serían los SysV , no funcionarían en BSD (opcional (XSI) en POSIX). También necesitaría ls -god file | awk '{print $3; exit}'
( -d
para que funcione en directorios, exit
para enlaces simbólicos con nuevas líneas en el destino). Los problemas con los archivos del dispositivo también permanecen.
wc -c
que informa el número de bytes.
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
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
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 stat
comando.
ls -l
y el stat
comando dan información confiable sobre el tamaño. No encontré ninguna referencia a lo contrario. ls -s
dará tamaño en número de bloques.
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.
du
imprime el tamaño en bloques de 1024 bytes, no un simple recuento de bytes.
du
proporciona una salida en número de unidades de 512 bytes. GNU du
usa kibibytes a menos que se llame con POSIXLY_CORRECT
en su entorno.
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.
gzip -v < file > /dev/null
para verificar la compresibilidad de un archivo.
case
declaración. case
es la construcción Bourne / POSIX para hacer coincidencia de patrones. [[...]]
es solo ksh / bash / zsh (con variaciones).
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 .
Otra forma compatible con POSIX sería usar awk
con 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 NR
se 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 awk
toma un argumento que por defecto significa length($0)
que es para la línea completa actual.
printf 'a\nb' | awk '{ sum+=length } END { print sum+NR }'
debería imprimir 3 pero imprime 4.
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
wc
lee el último bloque del archivo, en caso de que stat.st_size
fuera solo una aproximación (como para Linux /proc
y /sys
archivos). 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
El método más rápido y simple (IMO) es:
bash_var=$(stat -c %s /path/to/filename)
du
y wc
respuestas 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 .