Comment vérifier la taille d'un fichier à l'aide de Bash?

145

J'ai un script qui vérifie la taille 0, mais je pensais qu'il devait y avoir un moyen plus simple de vérifier la taille des fichiers à la place. Ie file.txtvaut normalement 100k; comment faire vérifier un script s'il est inférieur à 90k (y compris 0), et lui faire en obtenir une nouvelle copie car le fichier est corrompu dans ce cas.

Ce que j'utilise actuellement.

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
user349418
la source
1
unix.stackexchange.com/questions/16640/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Réponses:

250

[ -n file.txt ]ne vérifie pas sa taille, il vérifie que la chaîne file.txtest de longueur non nulle, donc elle réussira toujours.

Si vous voulez dire "la taille est différente de zéro", vous en avez besoin [ -s file.txt ].

Pour obtenir la taille d'un fichier, vous pouvez utiliser wc -cpour obtenir la taille (longueur du fichier) en octets:

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

Dans ce cas, il semble que c'est ce que vous voulez.

Mais pour info, si vous voulez savoir combien d'espace disque le fichier utilise, vous pouvez utiliser du -kpour obtenir la taille (espace disque utilisé) en kilo-octets:

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 vous avez besoin de plus de contrôle sur le format de sortie, vous pouvez également consulter stat. Sous Linux, vous commenceriez par quelque chose comme stat -c '%s' file.txt, et sur BSD / Mac OS X, quelque chose comme stat -f '%z' file.txt.

Mikel
la source
5
Pourquoi du -b "$file" | cut -f 1au lieu de stat -c '%s' "$file"? Ou stat --printf="%s" "$file"?
mivk
1
Seulement parce qu'il est plus portable. BSD et Linux stat ont des indicateurs différents.
Mikel
1
J'ai dû le modifier ... | cut -d' ' -f1pour le faire fonctionner sur Ubuntu.
Mikepote
8
Utilisez wc -c < "$file"(notez le <), auquel cas vous n'avez pas besoin de la | cut ...pièce (qui, telle que publiée, ne fonctionne pas sous OSX). La BLOCKSIZEvaleur minimale pour dusur OSX est 512.
mklement0
3
@PetriSirkkala Sur mon système Linux, wc -c <filenameutilise également fstatet seek? Notez que cela fstatprend un fd, pas un chemin.
Mikel
24

Cela me surprend que personne n'ait mentionné statde vérifier la taille du fichier. Certaines méthodes sont certainement meilleures: utiliser -spour savoir si le fichier est vide ou non est plus facile que toute autre chose si c'est tout ce que vous voulez. Et si vous voulez trouver des fichiers d'une taille, alors findc'est certainement la voie à suivre.

J'aime aussi dubeaucoup obtenir la taille du fichier en ko, mais, pour les octets, j'utiliserais stat:

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

size=$(stat -c%s $filename) # GNU stat?
Daniel C. Sobral
la source
2
statest une excellente idée, mais sur CentOS, c'est ce qui a fonctionné pour moi:size=$(stat -c%s $filename)
Oz Solomon
2
La différence entre GNU et BSD est ce qui, malheureusement, rend cette alternative un peu moins attrayante. :(
lapo
1
stat peut être trompeur si le fichier est clairsemé. Vous pouvez utiliser les blocs signalés par stat pour calculer l'espace utilisé.
Ajith Antony le
@AjithAntony C'est un point intéressant qui ne m'est pas venu à l'esprit. Je peux voir statque c'est la bonne chose dans certaines situations, et les fichiers épars ne sont pas pertinents dans la plupart des situations, mais certainement pas toutes.
Daniel
17

solution alternative avec awk et double parenthèse:

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

if ((SIZE<90000)) ; then 
    echo "less"; 
else 
    echo "not less"; 
fi
fstab
la source
1
Bien, mais ne fonctionnera pas sur OSX, où dune prend pas en charge -b. (Il peut être un choix de style conscient, mais juste de mentionner l'alternative: vous pouvez omettre l' $intérieur du préfixe (( ... ))lorsque les variables faisant référence: ((SIZE<90000)))
mklement0
1
En fait, c'était une modification d'un utilisateur précédent qui pensait qu'il était erroné d'omettre le$
fstab
2
@fstab, vous pouvez omettre awken utilisant read( bashcommande interne):read SIZE _ <<<$(du -sb "$FILENAME")
Jdamian
13

Si votre findgère cette syntaxe, vous pouvez l'utiliser:

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

Cela sortira file.txtvers stdout si et seulement si la taille de file.txtest inférieure à 90k. Pour exécuter un script scripts'il file.txta une taille inférieure à 90k:

find -maxdepth 1 -name "file.txt" -size -90k -exec script \;
gniourf_gniourf
la source
3
+1, mais pour que cela fonctionne aussi sur OSX, vous avez besoin d'un argument de répertoire cible explicite, par exemple:find . -maxdepth 1 -name "file.txt" -size -90k
mklement0
8

Si vous recherchez uniquement la taille d'un fichier:

$ cat $file | wc -c
> 203233
BananeNeil
la source
1
C'est peut-être la réponse la plus courte possible, mais c'est probablement aussi la plus lente. :)
SunSparc
2
Oui, mais certainement économiquement supérieur: Coût du temps d'ingénierie> Coût du temps de calcul
BananaNeil
8
wc -c "$file"a été donnée comme réponse en 2011 (il y a trois ans). Oui, wc -c "$file"a le problème qu'il génère le nom du fichier ainsi que le nombre de caractères, de sorte que les premières réponses ont ajouté une commande pour séparer le nombre. Mais wc -c < "$file", qui corrige ce problème, a été ajouté en tant que commentaire en mai 2014. Votre réponse est équivalente à cela, sauf qu'elle ajoute une «utilisation inutile de cat» . De plus, vous devez citer toutes les références de variables shell sauf si vous avez une bonne raison de ne pas le faire.
G-Man dit `` Réintégrer Monica ''
1
Vous pouvez rendre cela plus efficace en utilisant head -c au lieu de cat.if [$ (head -c 90000 $ file | wc -c) -lt 90000]; puis echo "Le fichier est plus petit que 90k"; Fi . Testé sur CentOS, il peut donc ou non fonctionner sur BSD ou OSX.
Kevin Keane
@BananaNeil comment faire ce processus toutes les 20 secondes pour que je puisse vérifier l'incrémentation de la taille du fichier, etc.?
A Sahra
6

Cela fonctionne à la fois sous Linux et 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
la source
5

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

la source
Si je comprends bien, le test doit être fait avec également la redirection de tuyau?: strace du --bytes $1 2>&1 >/dev/null | wc Si tel est le cas, alors sur l'architecture amd64 sur ArchLinux (généralement les dernières versions de tout) j'ai 45 lignes pour du, 46 lignes pour stat, 47 lignes pour wcet 72 lignes pour find.
VasiliNovikov
5
python -c 'import os; print (os.path.getsize("... filename ..."))'

portable, toutes les saveurs de python, évite les variations dans les dialectes statistiques

user6336835
la source
4

Pour obtenir la taille du fichier sous Linux et Mac OS X (et probablement dans d'autres BSD), il n'y a pas beaucoup d'options, et la plupart de celles suggérées ici ne fonctionneront que sur un seul système.

Étant donné f=/path/to/your/file,

qu'est-ce qui fonctionne sous Linux et Mac 's Bash:

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

ou

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

Les autres réponses fonctionnent bien sous Linux, mais pas sous Mac:

  • dun'a pas d' -boption sous Mac, et l'astuce BLOCKSIZE = 1 ne fonctionne pas ("la taille minimale du bloc est de 512", ce qui conduit à un résultat erroné)

  • cut -d' ' -f1 ne fonctionne pas car sur Mac, le nombre peut être aligné à droite, rempli d'espaces devant.

Donc, si vous avez besoin de quelque chose de flexible, il s'agit soit perlde l ' -sopérateur, soit de la wc -credirection vers awk '{print $1}'(awk ignorera le premier espace blanc).

Et bien sûr, concernant le reste de votre question initiale, utilisez l' opérateur -lt(ou -gt):

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

mivk
la source
3
+1; si vous savez que vous n'utiliserez la taille que dans un contexte arithmétique (où l'espace blanc de début est ignoré), vous pouvez simplifier en size=$(wc -c < "$f")(notez le <, ce qui fait wcrapporter uniquement un nombre). Re comparaison: n'oubliez pas le plus "bash-ful" if (( size < your_wanted_size )); then ...(et aussi [[ $size -lt $your_wanted_size ]]).
mklement0
3

D'après la réponse de gniourf_gniourf,

find "file.txt" -size -90k

écrira file.txtdans stdout si et seulement si la taille de file.txtest inférieure à 90 Ko, et

rechercher "file.txt" -size -90k -exec commande \;

exécutera la commande commandsi file.txtsa taille est inférieure à 90 Ko. J'ai testé cela sur Linux. De find(1),

… Les arguments de ligne de commande suivants (les options -H, -Let -P) sont considérés comme des noms de fichiers ou de répertoires à examiner, jusqu'au premier argument qui commence par «-»,…

(italiques ajoutés).

G-Man dit `` Réintégrer Monica ''
la source
1
ls -l $file | awk '{print $6}'

en supposant que la commande ls rapporte la taille du fichier à la colonne # 6

yeugeniuss
la source
1

J'utiliser du« s --thresholdpour cela. Je ne sais pas si cette option est disponible dans toutes les versions de, dumais elle est implémentée dans la version de GNU.

Citant le manuel de du (1) :

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

Voici ma solution, en utilisant du --threshold=pour le cas d'utilisation d'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

L'avantage de cela, c'est que vous dupouvez accepter un argument pour cette option dans un format connu - soit humain comme dans 10K, 10MiBou avec quoi vous vous sentez à l'aise - vous n'avez pas besoin de convertir manuellement entre les formats / unités car cela dugère cela.

Pour référence, voici l'explication de cet SIZEargument à partir de la page de manuel:

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
la source
+1 Excellente option. Malheureusement, certains d'entre nous sont coincés avec des versions plus anciennes de duqui ne le prennent pas en charge. L' --thresholdoption a été ajoutée dans coreutils 8.21, sorti en 2013 .
Amit Naidu du
1

D'accord, si vous êtes sur un Mac, faites ceci: stat -f %z "/Users/Example/config.log" c'est tout!

GarfExiXD
la source