web-dev-qa-db-fra.com

Un moyen portable pour obtenir la taille du fichier (en octets) dans le shell?

Sous Linux, j'utilise stat --format="%s" FILE, mais Solaris auquel j'ai accès n’a pas de commande stat. Que devrais-je utiliser alors?

J'écris des scripts Bash et je ne peux pas installer de nouveau logiciel sur le système.

J'ai déjà envisagé d'utiliser:

Perl -e '@x=stat(shift);print $x[7]' FILE

ou même:

ls -nl FILE | awk '{print $5}'

Mais aucun de ceux-ci ne semble raisonnable - exécuter Perl uniquement pour obtenir la taille du fichier? Ou exécuter 2 commandes pour faire la même chose?

106
user80168

wc -c < filename (abréviation de Nombre de mots, -c affiche le nombre d'octets) est une solution portable POSIX . Seul le format de sortie peut ne pas être uniforme sur toutes les plates-formes, car certains espaces peuvent être préfixés (comme c'est le cas pour Solaris).

N'omettez pas la redirection d'entrée. Lorsque le fichier est passé en argument, le nom du fichier est imprimé après le nombre d'octets.

Je craignais que cela ne fonctionne pas pour les fichiers binaires, mais cela fonctionne correctement sous Linux et Solaris. Vous pouvez l'essayer avec wc -c < /usr/bin/wc. De plus, les utilitaires POSIX sont garantis pour gérer les fichiers binaires , sauf indication contraire explicite.

195
Carl Smotricz

J'ai fini par écrire mon propre programme (très petit) pour afficher uniquement la taille. Plus d'informations ici: http://fwhacking.blogspot.com/2011/03/bfsize-print-file-size-in-bytes-and.html

Les deux méthodes les plus propres à mon avis avec les outils Linux courants sont les suivantes:

$ stat -c %s /usr/bin/stat
50000

$ wc -c < /usr/bin/wc
36912

Mais je ne veux tout simplement pas taper des paramètres ou transmettre la sortie simplement pour obtenir une taille de fichier, alors j'utilise ma propre taille de fichier.

35
fwhacking

Même si du imprime généralement l'utilisation du disque et non la taille réelle des données, GNU coreutils du peut imprimer la "taille apparente" du fichier en octets:

du -b FILE

Mais cela ne fonctionnera pas sous BSD, Solaris, macOS, ...

23
fwhacking

Enfin, j’ai décidé d’utiliser ls et le développement de tableaux bash:

TEMP=( $( ls -ln FILE ) )
SIZE=${TEMP[4]}

ce n'est pas vraiment agréable, mais au moins, il ne fait que 1 fork + execve, et il ne s'appuie pas sur un langage de programmation secondaire (Perl/Ruby/python/peu importe)

13
user80168

Solution la plus rapide entre plates-formes (utilise uniquement un fork () pour ls, ne tente pas de compter les caractères réels, ne génère pas de mots inutiles: awk, Perl, etc.).

Testé sous MacOS, Linux - peut nécessiter des modifications mineures pour Solaris:

__ln=( $( ls -Lon "$1" ) )
__size=${__ln[3]}
echo "Size is: $__size bytes"

Si nécessaire, simplifiez les arguments ls et ajustez le décalage dans $ {__ ln [3]}.

Remarque: suivra les liens symboliques.

8
Orwellophile

Les BSD ont stat avec différentes options de GNU), mais des fonctionnalités similaires.

stat -f %z <file name> 

Cela fonctionne sur macOS (testé sur 10.12), FreeBSD , NetBSD et OpenBSD .

7
user7504315

Si vous utilisez find de GNU fileutils:

size=$( find . -maxdepth 1 -type f -name filename -printf '%s' )

Malheureusement, les autres implémentations de find ne supportent généralement pas -maxdepth, ni -printf. C’est le cas, par exemple, de Solaris et macOS find.

4
Dennis Williamson

Lors du traitement ls -n sortie, vous pouvez utiliser les arguments de position, qui constituent le seul tableau et sont les seules variables locales dans le standard Shell. Enveloppez l'écrasement des arguments de position dans une fonction pour conserver les arguments d'origine dans votre script ou votre fonction.

getsize() { set -- $(ls -dn "$1") && echo $5; }
getsize FILE

Cela divise la sortie de ln -dn en fonction des paramètres de variable d’environnement IFS actuels, l’assigne aux arguments de position et fait écho au cinquième. Le -d s'assure que les répertoires sont gérés correctement et que le -n _ assure que les noms d’utilisateur et de groupe n’ont pas besoin d’être résolus, contrairement à -l. En outre, les noms d'utilisateurs et de groupes contenant des espaces pourraient théoriquement rompre la structure de ligne attendue; ils sont généralement refusés, mais cette possibilité oblige le programmeur à s'arrêter et à réfléchir.

4
Richard

Vous pouvez utiliser la commande find pour obtenir un ensemble de fichiers (ici, les fichiers temporaires sont extraits). Ensuite, vous pouvez utiliser la commande du pour obtenir la taille de fichier de chaque fichier sous une forme lisible par l'homme à l'aide de -h _ commutateur.

find $HOME -type f -name "*~" -exec du -h {} \;

SORTIE:

4.0K    /home/turing/Desktop/JavaExmp/TwoButtons.Java~
4.0K    /home/turing/Desktop/JavaExmp/MyDrawPanel.Java~
4.0K    /home/turing/Desktop/JavaExmp/Instream.Java~
4.0K    /home/turing/Desktop/JavaExmp/RandomDemo.Java~
4.0K    /home/turing/Desktop/JavaExmp/Buff.Java~
4.0K    /home/turing/Desktop/JavaExmp/SimpleGui2.Java~
3
Abhishek Singh

Votre premier exemple Perl ne me semble pas déraisonnable.

C'est pour des raisons de ce type que j'ai migré de l'écriture de scripts Shell (en bash/sh, etc.) à l'écriture de tous les scripts sauf les plus triviaux de Perl. Je me suis rendu compte que je devais lancer Perl pour des besoins particuliers, et au fur et à mesure que je le faisais, je me suis rendu compte que l'écriture des scripts en Perl était probablement plus puissante (en termes de langage et du grand nombre de bibliothèques disponibles via - CPAN ) et un moyen plus efficace de réaliser ce que je voulais.

Notez que d'autres langages de script Shell (par exemple, python/Ruby) auront sans aucun doute des fonctionnalités similaires, et vous voudrez peut-être les évaluer pour vos besoins. Je ne discute que de Perl car c'est le langage que j'utilise et que je connais bien.

2
Brian Agnew