desarrollo-web-br-bd.com

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

¿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?

271
haunted85

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 @ respuesta de chbrown para saber cómo usar stat en la terminal en Mac OS X.

262
b01
file_size_kb=`du -k "$filename" | cut -f1`

El problema con el uso de stat es que es una extensión GNU (Linux). du -k y cut -f1 están especificados por POSIX y, por lo tanto, son portables a 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 el formato exacto de la salida no está especificado, 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.

97
Nemo

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 flujo 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 buscaba como variable de Shell, como se menciona en Gilles a continuación.

size="$(wc -c <"$filename")"
79
Eugéne

Los BSD (macOS) 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.
  • ... la sección FORMATOS ...
  • z: El tamaño del archivo en bytes.

Así que todos juntos ahora:

stat -f%z myfile1.txt

NOTA: consulte @ respuesta de b01 para saber cómo usar el comando stat en sistemas GNU/Linux. :)

53
chbrown

Depende de lo que quiera decir con 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 implementaciones wc 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 de nuevo y para cosas como /dev/zero O /dev/random Que son de tamaño infinito, tomará un tiempo. Eso también significa que necesita el permiso read 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 implementaciones wc 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 ningún resultado (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 hace el más eficiente para archivos regulares en ese Shell.

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

Esos reportan información encontrada en el inodo. Una de esas informaciones es el atributo st_size. 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 implementaciones wc -c 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:

  • IRIX stat (90's):

    stat -qLs -- "$file"
    

    devuelve el atributo st_size 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.

  • zshstat builtin (ahora también conocido como zstat) en el módulo zsh/stat (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.

  • GNU stat (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 zshstat.

  • BSDs stat (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(), por lo que no funcionará en enlaces simbólicos) y con el que podría postprocesar, por ejemplo:

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

(gracias @JeffSchaller por el ayuda a 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 comando stat, lo mismo podría lograrse con GNU find comando 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 predicado find (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 para lo mismo después de la resolución del enlace simbólico. Eso no funciona para los archivos del dispositivo, aunque donde los 5th El campo es el número principal del dispositivo en lugar del tamaño.

Para los dispositivos de bloque, los sistemas donde stat() devuelve 0 para st_size, Generalmente tienen otras API para informar el tamaño del dispositivo de bloque. Por ejemplo, Linux tiene el BLKGETSIZE64ioctl(), y la mayoría de las distribuciones de Linux ahora se envían con un comando blockdev 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 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 módulo zsh/system):

    {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 canalizaciones con nombre, hemos visto que algunos sistemas (AIX, Solaris, HP/UX al menos) hacen que la cantidad de datos en el búfer de canalizaciones esté disponible en stat() 's st_size. Algunos (como Linux o FreeBSD) no lo hacen.

Al menos en Linux, puede usar FIONREADioctl() 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 fuser puede no ser capaz de 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 es típicamente lo que 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).
  • GNU find -- "$file" -printf '%b\n'
  • zstat -L +block -- $file
  • GNU stat -c %b -- "$file"
  • BSD stat -f %b -- "$file"
  • Perl -le 'print((lstat shift)[12])' -- "$file"
32

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

22

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
9
user150821

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 siguiente ejemplo, 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: Esto aparentemente no es tan confiable como el comando stat.

8
Druckles

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

Yo prefiero du -h filename, que le da el tamaño en un formato legible para humanos.

5
Teddy

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; Raspberry Pi no tiene stat pero sí tiene awk.

3
findrbot_admin

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.

3
oligofren

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 a 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 función length() en awk toma un argumento que por defecto significa length($0) que es para la línea completa actual.

0
Inian