web-dev-qa-db-fra.com

Comment puis-je obtenir la taille d'un fichier dans un script bash?

Comment puis-je obtenir la taille d'un fichier dans un script bash?

Comment attribuer cela à une variable bash afin de pouvoir l'utiliser plus tard?

271
haunted85

Votre meilleur pari si sur un système GNU:

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

De man stat :

% s taille totale, en octets

Dans un script bash:

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

REMARQUE: voir réponse de @ chbrown pour savoir comment utiliser stat dans le terminal sur Mac OS X.

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

Le problème avec l'utilisation de stat est qu'il s'agit d'une extension GNU (Linux). du -k et cut -f1 sont spécifiés par POSIX et sont donc portables sur n'importe quel système Unix.

Solaris, par exemple, est livré avec bash mais pas avec stat. Ce n'est donc pas entièrement hypothétique.

ls a un problème similaire en ce que le format exact de la sortie n'est pas spécifié, donc l'analyse de sa sortie ne peut pas être effectuée de manière portable. du -h est également une extension GNU.

Respectez les constructions portables dans la mesure du possible et vous faciliterez la vie de quelqu'un à l'avenir. Peut-être le vôtre.

97
Nemo

Vous pouvez également utiliser la commande "Word count" (wc):

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

Le problème avec wc est qu'il va ajouter le nom de fichier et indenter la sortie. Par exemple:

$ wc -c somefile.txt
    1160 somefile.txt

Si vous souhaitez éviter de chaîner un langage entièrement interprété ou un éditeur de flux juste pour obtenir un nombre de fichiers, redirigez simplement l'entrée du fichier afin que wc ne voie jamais le nom du fichier:

wc -c < "$filename"

Ce dernier formulaire peut être utilisé avec la substitution de commandes pour récupérer facilement la valeur que vous cherchiez en tant que variable Shell, comme mentionné par Gilles ci-dessous.

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

BSD (macOS) stat a un indicateur d'argument de format différent et différents spécificateurs de champ. De man stat(1):

  • -f format: Afficher les informations au format spécifié. Voir la section FORMATS pour une description des formats valides.
  • ... la section FORMATS ...
  • z: La taille du fichier en octets.

Alors tous ensemble maintenant:

stat -f%z myfile1.txt

REMARQUE: voir réponse de @ b01 pour savoir comment utiliser la commande stat sur les systèmes GNU/Linux. :)

53
chbrown

Cela dépend de ce que vous entendez par taille .

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

vous donnera le nombre d'octets pouvant être lus à partir du fichier. IOW, c'est la taille du contenu du fichier. Il lira cependant le contenu du fichier (sauf si le fichier est un fichier normal ou un lien symbolique vers un fichier normal dans la plupart des implémentations wc comme optimisation). Cela peut avoir des effets secondaires. Par exemple, pour un canal nommé, ce qui a été lu ne peut plus être lu à nouveau et pour des choses comme /dev/zero Ou /dev/random Qui sont de taille infinie, cela va prendre un certain temps. Cela signifie également que vous avez besoin d'une autorisation read sur le fichier et que le dernier horodatage d'accès du fichier peut être mis à jour.

C'est standard et portable, mais notez que certaines implémentations wc peuvent inclure des blancs de début dans cette sortie. Une façon de s'en débarrasser est d'utiliser:

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

ou pour éviter une erreur sur une expression arithmétique vide dans dash ou yash lorsque wc ne produit aucune sortie (comme lorsque le fichier ne peut pas être ouvert):

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

ksh93 A wc intégré (à condition que vous l'activiez, vous pouvez également l'appeler en tant que command /opt/ast/bin/wc) Ce qui en fait le plus efficace pour les fichiers normaux dans ce Shell.

Divers systèmes ont une commande appelée stat qui est une interface avec les appels système stat() ou lstat().

Ceux-ci rapportent des informations trouvées dans l'inode. L'une de ces informations est l'attribut st_size. Pour les fichiers normaux, c'est la taille du contenu (combien de données pourraient être lues en l'absence d'erreur (c'est ce que la plupart des implémentations wc -c Utilisent dans leur optimisation)). Pour les liens symboliques, c'est la taille en octets du chemin cible. Pour les canaux nommés, selon le système, il s'agit de 0 ou du nombre d'octets actuellement dans le tampon de canal. Idem pour les périphériques de bloc où, selon le système, vous obtenez 0 ou la taille en octets du stockage sous-jacent.

Vous n'avez pas besoin d'une autorisation de lecture sur le fichier pour obtenir ces informations, mais uniquement une autorisation de recherche sur le répertoire auquel il est lié.

Par ordre chronologique, il y a:

  • IRIX stat (90's):

    stat -qLs -- "$file"
    

    renvoie l'attribut st_size de $file (lstat()) ou:

    stat -s -- "$file"
    

    idem sauf lorsque $file est un lien symbolique auquel cas c'est le st_size du fichier après la résolution du lien symbolique.

  • zshstat builtin (désormais également appelé zstat) dans le module zsh/stat (chargé avec zmodload zsh/stat ) (1997):

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

    ou pour stocker dans une variable:

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

    évidemment, c'est le plus efficace dans ce Shell.

  • GNU stat (2001); également dans BusyBox stat depuis 2005 (copié depuis GNU stat):

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

    (notez que la signification de -L est inversée par rapport à IRIX ou zshstat.

  • BSD stat (2002):

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

Ou vous pouvez utiliser la fonction stat()/lstat() d'un langage de script comme Perl:

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

AIX a également une commande istat qui videra toutes les informations stat() (pas lstat(), donc ne fonctionnera pas sur les liens symboliques) et avec lequel vous pouvez post-traiter, par exemple:

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

(merci @JeffSchaller pour le aide à trouver les détails ).

Dans tcsh:

@ size = -Z $file:q

(taille après la résolution du lien symbolique)

Bien avant GNU a introduit sa commande stat, la même chose pouvait être obtenue avec GNU find command avec sa -printf Prédicat (déjà en 1991):

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

Cependant, un problème est que cela ne fonctionne pas si $file Commence par - Ou est un prédicat find (comme !, (. ..).

La commande standard pour obtenir les informations stat()/lstat() est ls.

POSIX, vous pouvez faire:

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

et ajoutez -L pour la même chose après la résolution du lien symbolique. Cela ne fonctionne pas pour les fichiers de périphérique, mais là où le 5e champ est le numéro majeur de l'appareil au lieu de la taille.

Pour les périphériques de bloc, les systèmes où stat() renvoie 0 pour st_size, Ont généralement d'autres API pour signaler la taille du périphérique de bloc. Par exemple, Linux a la BLKGETSIZE64ioctl(), et la plupart des distributions Linux sont désormais livrées avec une commande blockdev qui peut l'utiliser:

blockdev --getsize64 -- "$device_file"

Cependant, vous avez besoin d'une autorisation de lecture sur le fichier du périphérique pour cela. Il est généralement possible de dériver la taille par d'autres moyens. Par exemple (toujours sous Linux):

lsblk -bdno size -- "$device_file"

Devrait fonctionner sauf pour les appareils vides.

Une approche qui fonctionne pour tous les fichiers recherchables (inclut donc les fichiers normaux, la plupart des périphériques de bloc et certains périphériques de caractères) consiste à ouvrir le fichier et à rechercher jusqu'à la fin. :

  • Avec zsh (après avoir chargé le module zsh/system):

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

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

    ou

    { size=$(<#((EOF))); } < "$file"
    
  • avec Perl:

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

Pour les canaux nommés, nous avons vu que certains systèmes (AIX, Solaris, HP/UX au moins) rendent la quantité de données dans le tampon de canal disponible dans st_size De stat(). Certains (comme Linux ou FreeBSD) ne le font pas.

Sous Linux au moins, vous pouvez utiliser la fonction FIONREADioctl() après avoir ouvert le tube (en mode lecture + écriture pour éviter qu'il ne se bloque):

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

Notez cependant que bien qu'il ne lise pas le contenu du tuyau, la simple ouverture du tuyau nommé ici peut toujours avoir des effets secondaires. Nous utilisons fuser pour vérifier d'abord que certains processus ont déjà ouvert le tuyau pour y remédier, mais ce n'est pas infaillible car fuser peut ne pas être en mesure de vérifier tous les processus.

Jusqu'à présent, nous n'avons considéré que la taille des données primaires associées aux fichiers. Cela ne prend pas en compte la taille des métadonnées et toute l'infrastructure de support nécessaire pour stocker ce fichier.

Un autre attribut inode renvoyé par stat() est st_blocks. C'est le nombre de blocs de 512 octets qui sont utilisés pour stocker les données du fichier (et parfois certaines de ses métadonnées comme les attributs étendus sur les systèmes de fichiers ext4 sous Linux). Cela n'inclut pas l'inode lui-même, ni les entrées dans les répertoires auxquels le fichier est lié.

La taille et l'utilisation du disque ne sont pas nécessairement étroitement liées car la compression, la rareté (parfois certaines métadonnées), une infrastructure supplémentaire comme les blocs indirects dans certains systèmes de fichiers ont une influence sur ces derniers.

C'est généralement ce que du utilise pour signaler l'utilisation du disque. La plupart des commandes répertoriées ci-dessus pourront vous obtenir ces informations.

  • POSIXLY_CORRECT=1 ls -sd -- "$file" | awk '{print $1; exit}'
  • POSIXLY_CORRECT=1 du -s -- "$file" (Pas pour les répertoires où cela inclurait l'utilisation du disque des fichiers à l'intérieur).
  • 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

Ce script combine plusieurs façons de calculer la taille du fichier:

(
  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}'

Le script fonctionne sur de nombreux systèmes Unix, notamment Linux, BSD, OSX, Solaris, SunOS, etc.

La taille du fichier indique le nombre d'octets. Il s'agit de la taille apparente, qui correspond aux octets que le fichier utilise sur un disque type, sans compression spéciale, ni zones éparses spéciales, ni blocs non alloués, etc.

Ce script a une version de production avec plus d'aide et plus d'options ici: https://github.com/SixArm/file-size

22
joelparkerhenderson

stat semble faire cela avec le moins d'appels système:

$ 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 vous fournira de nombreuses informations sur un fichier, notamment sa taille, ses autorisations et son propriétaire.

La taille du fichier dans la cinquième colonne et s'affiche en octets. Dans l'exemple ci-dessous, la taille du fichier est légèrement inférieure à 2 Ko:

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

Edit: Ce n'est apparemment pas aussi fiable que la commande stat.

8
Druckles

du filename vous indiquera l'utilisation du disque en octets.

Je préfère du -h filename, qui vous donne la taille dans un format lisible par l'homme.

5
Teddy

J'ai trouvé un liner AWK 1, et il y avait un bug mais je l'ai corrigé. J'ai également ajouté des PetaBytes après 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] }')

Étant donné que stat n'est pas sur tous les systèmes, vous pouvez presque toujours utiliser la solution AWK. Exemple; le Raspberry Pi n'a pas stat mais il a awk.

3
findrbot_admin

Créez de petites fonctions utilitaires dans vos scripts Shell que vous pouvez déléguer.

Exemple

#! /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

D'après les informations de @ Stéphane Chazelas.

3
oligofren

Une autre manière conforme à POSIX serait d'utiliser awk avec sa fonction length() qui renvoie la longueur, en caractères sur chaque ligne du fichier d'entrée, à l'exclusion des caractères de nouvelle ligne. Donc en faisant

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

nous nous assurons que NR est ajouté à sum, ce qui entraîne le nombre total de caractères et le nombre total de sauts de ligne rencontrés dans le fichier. La fonction length() dans awk prend un argument qui signifie par défaut length($0) qui est pour la ligne entière courante.

0
Inian