Wie kann ich die Größe einer Datei in einem Bash-Skript ermitteln?
Wie ordne ich dies einer Bash-Variablen zu, damit ich sie später verwenden kann?
pv
und cat
für einen Kopierbefehl, der den Fortschritt und die ETA anzeigt :)
Wie kann ich die Größe einer Datei in einem Bash-Skript ermitteln?
Wie ordne ich dies einer Bash-Variablen zu, damit ich sie später verwenden kann?
pv
und cat
für einen Kopierbefehl, der den Fortschritt und die ETA anzeigt :)
Antworten:
Ihre beste Wahl, wenn Sie auf einem GNU-System arbeiten:
stat --printf="%s" file.any
Von mann stat :
% s Gesamtgröße in Byte
In einem Bash-Skript:
#!/bin/bash
FILENAME=/home/heiko/dummy/packages.txt
FILESIZE=$(stat -c%s "$FILENAME")
echo "Size of $FILENAME = $FILESIZE bytes."
HINWEIS: Informationen zur Verwendung von stat im Terminal unter Mac OS X finden Sie in der Antwort von @ chbrown.
stat
ist der einfachste Weg, vorausgesetzt, Sie verwenden Linux oder Cygwin ( stat
nicht Standard). wc -c
wie von Eugéne vorgeschlagen, ist portabel.
stat: illegal option -- c
stat --printf="%s" file.txt
gibt nichts auf Debian Jessie aus ...
stat -f%z myfile.tar
man stat
sagt, dass --printf die nachfolgende Newline weglässt. Verwenden Sie --format
oder -c
, um die Ausgabe anzuzeigen. Gewinnen Sie mehr Einsicht im Vergleich stat --printf="%s" file.any | xxd -
zustat -c "%s" file.any | xxd -
file_size_kb=`du -k "$filename" | cut -f1`
Das Problem bei der Verwendung stat
ist, dass es sich um eine GNU (Linux) -Erweiterung handelt. du -k
und cut -f1
werden von POSIX spezifiziert und sind daher auf jedes Unix-System portierbar.
Solaris wird zum Beispiel mit bash ausgeliefert, aber nicht mit stat
. Das ist also nicht ganz hypothetisch.
ls
Ein ähnliches Problem besteht darin, dass das genaue Format der Ausgabe nicht angegeben ist, sodass das Parsen der Ausgabe nicht portabel durchgeführt werden kann. du -h
ist auch eine GNU-Erweiterung.
Wenn möglich, halten Sie sich an tragbare Konstrukte und Sie werden das Leben von jemandem in Zukunft einfacher machen. Vielleicht deine eigene.
du
gibt nicht die Größe der Datei an, sondern gibt einen Hinweis darauf, wie viel Speicherplatz die Datei belegt, was sich geringfügig unterscheidet (normalerweise du
ist die angegebene Größe die Größe der Datei, aufgerundet auf die nächste Anzahl von Blöcken, bei denen ein Block vorhanden ist beträgt typischerweise 512B oder 1kB oder 4kB).
--bytes
oder -b
anstelle von -k
die akzeptierte Antwort sein.
-h
Option ("Mensch") vondu
liefert die am besten geeignete Antwort für allgemeine Fälle file_size=`du -h "$filename" | cut -f1
:, da K (Kilobyte), M (Megabyte) oder G (Gigabyte) angezeigt werden.
Sie können auch den Befehl "word count" ( wc
) verwenden:
wc -c "$filename" | awk '{print $1}'
Das Problem dabei wc
ist, dass der Dateiname hinzugefügt und die Ausgabe eingerückt wird. Zum Beispiel:
$ wc -c somefile.txt
1160 somefile.txt
Wenn Sie vermeiden möchten, einen vollständig interpretierten Sprach- oder Stream-Editor zu verketten, um die Dateigröße zu ermitteln, leiten Sie einfach die Eingabe aus der Datei um, sodass wc
der Dateiname nicht angezeigt wird:
wc -c < "$filename"
Diese letzte Form kann mit der Befehlsersetzung verwendet werden, um den gesuchten Wert als Shell-Variable zu erfassen, wie von Gilles unten erwähnt.
size="$(wc -c <"$filename")"
wc -c <"$FILENAME"
ergibt die größe bei keiner anderen kruft also size=$(wc -c <"$FILENAME")
.
wc -c < file
scheint sehr schnell zu sein, zumindest unter OS X. Ich vermute, dass wc die Köpfe hat, um zu versuchen, die Datei zu statisieren, wenn nur -c angegeben wird.
wc -c
verwendet fstat
, sucht dann aber den vorletzten Block der Datei und liest die letzten bis zu st_blksize
Bytes. Anscheinend liegt dies daran, dass Dateien in Linux /proc
und /sys
z. B. nur ungefähre stat-Größen haben und wc
die tatsächliche Größe angeben möchten, nicht die stat-gemeldete Größe. Ich denke, es wäre seltsam wc -c
, eine andere Größe als zu melden wc
, aber es ist nicht ratsam, Daten aus der Datei zu lesen, wenn es sich um eine normale Festplattendatei handelt und sie sich nicht im Speicher befindet. Oder noch schlimmer, Near-Line-Bandspeicher ...
printf
sieht die Einrückung noch aus, zB printf "Size: $size"
-> size: <4 spaces> 54339
. Auf der anderen Seite echo
ignoriert das Leerzeichen. Wie kann man es konsistent machen?
fstat
. Laufen strace wc -c </etc/passwd
Sie und Sie können sehen, was es tut.
BSDs (Mac OS Xs) stat
haben ein unterschiedliches Formatargument-Flag und unterschiedliche Feldspezifizierer. Von man stat(1)
:
-f format
: Informationen im angegebenen Format anzeigen. Im Abschnitt FORMATE finden Sie eine Beschreibung der gültigen Formate.z
: Die Größe der Datei in Bytes.Also alles zusammen jetzt:
stat -f%z myfile1.txt
Kommt darauf an, was du mit Größe meinst .
size=$(wc -c < "$file")
gibt die Anzahl der Bytes an, die aus der Datei gelesen werden können. IOW, es ist die Größe des Inhalts der Datei. Der Inhalt der Datei wird jedoch gelesen (es sei denn, die Datei ist eine reguläre Datei oder ein Symlink zu einer regulären Datei, was in den meisten wc
Implementierungen eine Optimierung darstellt). Das kann Nebenwirkungen haben. Zum Beispiel kann für eine Named Pipe, was gelesen wurde, nicht mehr wieder gelesen werden und für Dinge wie /dev/zero
oder /dev/random
die von unendlicher Größe, wird es eine Weile dauern. Das bedeutet auch, dass Sie eine read
Berechtigung für die Datei benötigen und der Zeitstempel des letzten Zugriffs der Datei möglicherweise aktualisiert wird.
Das ist Standard und portabel. Beachten Sie jedoch, dass einige wc
Implementierungen führende Leerzeichen in dieser Ausgabe enthalten können. Eine Möglichkeit, sie loszuwerden, besteht darin, Folgendes zu verwenden:
size=$(($(wc -c < "$file")))
oder um einen Fehler bezüglich eines leeren arithmetischen Ausdrucks in dash
oder yash
wenn wc
keine Ausgabe erzeugt wird (wie wenn die Datei nicht geöffnet werden kann) zu vermeiden :
size=$(($(wc -c < "$file") +0))
ksh93
has wc
builtin (vorausgesetzt, Sie aktivieren es, Sie können es auch aufrufen als command /opt/ast/bin/wc
), wodurch es für reguläre Dateien in dieser Shell am effizientesten ist.
Verschiedene Systeme haben einen Befehl stat
, der als Schnittstelle zu den Systemaufrufen stat()
oder bezeichnet lstat()
wird.
Diese Berichtsinformationen befinden sich in der Inode. Eine dieser Informationen ist das st_size
Attribut. Bei regulären Dateien entspricht dies der Größe des Inhalts (wie viele Daten ohne Fehler daraus gelesen werden konnten (dies wird von den meisten wc -c
Implementierungen für die Optimierung verwendet)). Bei Symlinks entspricht dies der Größe des Zielpfads in Byte. Bei Named Pipes ist es je nach System entweder 0 oder die Anzahl der Bytes, die sich derzeit im Pipe-Puffer befinden. Dasselbe gilt für Blockgeräte, bei denen je nach System 0 oder die Größe des zugrunde liegenden Speichers in Byte angegeben wird.
Sie benötigen keine Leseberechtigung für die Datei, um diese Informationen abzurufen, sondern nur die Suchberechtigung für das Verzeichnis, mit dem sie verknüpft ist.
In chronologischer Reihenfolge gibt es:
IRIXstat
(90er Jahre):
stat -qLs -- "$file"
liefert das st_size
Attribut von $file
( lstat()
) oder:
stat -s -- "$file"
Das Gleiche gilt, außer wenn $file
es sich um einen Symlink handelt. In diesem Fall handelt es sich um den st_size
der Datei nach der Auflösung des Symlinks.
zsh
stat
eingebaut (jetzt auch bekannt als zstat
) in das zsh/stat
Modul (geladen mit zmodload zsh/stat
) (1997):
stat -L +size -- $file # st_size of file
stat +size -- $file # after symlink resolution
oder in einer Variablen speichern:
stat -L -A size +size -- $file
Offensichtlich ist das die effizienteste in dieser Shell.
GNUstat
(2001); stat
seit 2005 auch in BusyBox (kopiert von GNU stat
):
stat -c %s -- "$file" # st_size of file
stat -Lc %s -- "$file" # after symlink resolution
(Beachten Sie, dass die Bedeutung von -L
im Vergleich zu IRIX oder umgekehrt ist zsh
stat
.
BSDsstat
(2002):
stat -f %z -- "$file" # st_size of file
stat -Lf %z -- "$file" # after symlink resolution
Oder Sie können die Verwendung stat()
/ lstat()
Funktion einiger Skriptsprache wie perl
:
perl -le 'print((lstat shift)[7])' -- "$file"
AIX verfügt auch über einen istat
Befehl, der alle Informationen ausgibt stat()
(nicht lstat()
, funktioniert also nicht bei Symlinks) und mit dem Sie nachbearbeiten können, zum Beispiel:
LC_ALL=C istat "$file" | awk 'NR == 4 {print $5}'
(danke @JeffSchaller für die Hilfe beim Herausfinden der Details ).
In tcsh
:
@ size = -Z $file:q
(Größe nach Symlinkauflösung)
Lange bevor GNU seinen stat
Befehl einführte , konnte dasselbe mit dem GNU- find
Befehl mit seinem -printf
Prädikat erreicht werden (bereits 1991):
find -- "$file" -prune -printf '%s\n' # st_size of file
find -L -- "$file" -prune -printf '%s\n' # after symlink resolution
Ein Problem ist aber, dass nicht funktioniert , wenn $file
beginnt mit -
oder ist ein find
Prädikat (wie !
, (
...).
Der Standardbefehl zum Abrufen der stat()
/ lstat()
-Information lautet ls
.
POSIXly können Sie tun:
LC_ALL=C ls -dn -- "$file" | awk '{print $5; exit}'
und -L
für das gleiche nach Symlink-Auflösung hinzufügen . Dies funktioniert jedoch nicht für Gerätedateien, bei denen das fünfte Feld die Hauptnummer des Geräts anstelle der Größe ist.
Bei Blockgeräten haben Systeme, für stat()
die 0 zurückgegeben wird st_size
, normalerweise andere APIs, um die Größe des Blockgeräts zu melden. Zum Beispiel verfügt Linux über die BLKGETSIZE64
ioctl()
und die meisten Linux-Distributionen werden jetzt mit einem blockdev
Befehl ausgeliefert, der diese verwenden kann:
blockdev --getsize64 -- "$device_file"
Dafür benötigen Sie jedoch eine Leseberechtigung für die Gerätedatei. Es ist normalerweise möglich, die Größe auf andere Weise abzuleiten. Zum Beispiel (noch unter Linux):
lsblk -bdno size -- "$device_file"
Sollte funktionieren, außer für leere Geräte.
Ein Ansatz, der für alle durchsuchbaren Dateien funktioniert (einschließlich regulärer Dateien, der meisten Blockgeräte und einiger Zeichengeräte), besteht darin, die Datei zu öffnen und bis zum Ende zu suchen:
Mit zsh
(nach dem Laden des zsh/system
Moduls):
{sysseek -w end 0 && size=$((systell(0)))} < $file
Mit ksh93
:
< "$file" <#((size=EOF))
oder
{ size=$(<#((EOF))); } < "$file"
mit perl
:
perl -le 'seek STDIN, 0, 2 or die "seek: $!"; print tell STDIN' < "$file"
Für Named Pipes, haben wir gesehen , dass einige Systeme (AIX, Solaris, HP / UX zumindest) die Datenmenge in dem Rohrpuffer in zur Verfügung stellen stat()
ist st_size
. Einige (wie Linux oder FreeBSD) tun dies nicht.
Zumindest unter Linux können Sie das verwenden, FIONREAD
ioctl()
nachdem Sie die Pipe geöffnet haben (im Lese- und Schreibmodus, um ein Hängen zu vermeiden):
fuser -s -- "$fifo_file" &&
perl -le 'require "sys/ioctl.ph";
ioctl(STDIN, &FIONREAD, $n) or die$!;
print unpack "L", $n' <> "$fifo_file"
Beachten Sie jedoch, dass der Inhalt der Pipe zwar nicht gelesen wird , das bloße Öffnen der benannten Pipe jedoch dennoch Nebenwirkungen haben kann. Wir fuser
überprüfen zunächst, ob in einem Prozess bereits eine Pipe offen ist, um dies zu beheben. Dies ist jedoch nicht kinderleicht, da fuser
möglicherweise nicht alle Prozesse überprüft werden können.
Bisher haben wir nur die Größe der Primärdaten in Betracht gezogen, die mit den Dateien verknüpft sind. Dies berücksichtigt nicht die Größe der Metadaten und die gesamte unterstützende Infrastruktur, die zum Speichern dieser Datei erforderlich ist.
Ein weiteres von zurückgegebenes Inode-Attribut stat()
ist st_blocks
. Das ist die Anzahl von 512-Byte-Blöcken, die zum Speichern der Daten der Datei verwendet werden (und manchmal auch einiger ihrer Metadaten wie der erweiterten Attribute auf ext4-Dateisystemen unter Linux). Dies schließt weder den Inode selbst noch die Einträge in den Verzeichnissen ein, mit denen die Datei verknüpft ist.
Größe und Datenträgerverwendung hängen nicht unbedingt eng zusammen, da Komprimierung, Spärlichkeit (manchmal einige Metadaten) und zusätzliche Infrastruktur wie indirekte Blöcke in einigen Dateisystemen Einfluss auf letztere haben.
Dies wird normalerweise du
verwendet, um die Festplattennutzung zu melden. Mit den meisten der oben aufgeführten Befehle können Sie diese Informationen abrufen.
POSIXLY_CORRECT=1 ls -sd -- "$file" | awk '{print $1; exit}'
POSIXLY_CORRECT=1 du -s -- "$file"
(Nicht für Verzeichnisse, in denen die Datenträgerverwendung der Dateien enthalten wäre).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
verwendet fstat
, liest dann aber die letzten bis zu st_blksize
Bytes. Anscheinend liegt dies daran, dass Dateien in Linux /proc
und /sys
z. B. Stat-Größen nur ungefähr sind . Dies ist gut für die Korrektheit, aber schlecht, wenn sich das Ende der Datei auf der Festplatte und nicht im Speicher befindet (insbesondere, wenn es für viele Dateien in einer Schleife verwendet wird). Und sehr schlecht, wenn die Datei auf Nearline-Bandspeicher oder z. B. ein FUSE-Dateisystem mit transparenter Dekomprimierung migriert wird.
ls -go file | awk '{print $3}'
-go
wären die SysV, sie würden auf BSDs nicht funktionieren (optional (XSI) in POSIX). Sie müssten auch ls -god file | awk '{print $3; exit}'
( -d
damit es auf Verzeichnissen funktioniert, exit
für Symlinks mit Zeilenumbrüchen im Ziel). Die Probleme mit Gerätedateien bleiben ebenfalls bestehen.
wc -c
die Anzahl der Bytes.
Dieses Skript kombiniert viele Möglichkeiten, um die Dateigröße zu berechnen:
(
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}'
Das Skript funktioniert auf vielen Unix-Systemen, einschließlich Linux, BSD, OSX, Solaris, SunOS usw.
Die Dateigröße gibt die Anzahl der Bytes an. Dies ist die scheinbare Größe, dh die Bytes, die die Datei auf einem typischen Datenträger ohne besondere Komprimierung, ohne besondere Bereiche mit geringer Dichte oder ohne zugewiesene Blöcke usw. verwendet.
Dieses Skript enthält eine Produktionsversion mit mehr Hilfe und mehr Optionen: https://github.com/SixArm/file-size
stat scheint dies mit den wenigsten Systemaufrufen zu tun:
$ 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
gibt Ihnen viele Informationen über eine Datei, einschließlich Dateigröße, Berechtigungen und Eigentümer.
Die Dateigröße in der fünften Spalte und wird in Bytes angezeigt. Im folgenden Beispiel beträgt die Dateigröße knapp 2 KB:
-rw-r--r-- 1 user owner 1985 2011-07-12 16:48 index.php
Bearbeiten: Dies ist anscheinend nicht so zuverlässig wie der stat
Befehl.
ls -l
und stat
Befehl geben zuverlässige Größeninformationen. Ich habe keinen Hinweis auf das Gegenteil gefunden. ls -s
gibt die Größe in Anzahl von Blöcken an.
du filename
Zeigt die Festplattennutzung in Bytes an.
Ich bevorzuge du -h filename
, was dir die Größe in einem für Menschen lesbaren Format gibt.
du
druckt die Größe in Blöcken von 1024 Bytes aus, keine einfache Anzahl von Bytes.
du
eine Ausgabe in 512-Byte-Einheiten liefert. GNU du
verwendet stattdessen Kibibytes, sofern dies nicht POSIXLY_CORRECT
in seiner Umgebung mit aufgerufen wird .
Erstellen Sie in Ihren Shell-Skripten kleine Dienstprogrammfunktionen, an die Sie delegieren können.
Beispiel
#! /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
Gestützt auf Informationen aus der Antwort von @ Stéphane Chazelas.
gzip -v < file > /dev/null
, um die Komprimierbarkeit einer Datei zu überprüfen.
case
Aussage verwenden möchten . case
ist das Bourne / POSIX-Konstrukt für den Mustervergleich. [[...]]
ist nur ksh / bash / zsh (mit Variationen).
Ich habe einen AWK 1 Liner gefunden und er hatte einen Fehler, aber ich habe ihn behoben. Ich habe auch in PetaBytes nach TeraBytes hinzugefügt.
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] }')
Da stat nicht auf jedem einzelnen System vorhanden ist, können Sie die AWK-Lösung fast immer verwenden. Beispiel; Der Raspberry Pi hat keinen Status , aber einen awk .
Eine andere POSIX-konforme Methode wäre die Verwendung awk
der length()
Funktion, die die Länge in Zeichen in jeder Zeile der Eingabedatei ohne die Zeilenumbrüche zurückgibt. Also indem du tust
awk '{ sum+=length } END { print sum+NR }' file
Wir stellen sicher, dass NR
hinzugefügt wird sum
, wodurch sich die Gesamtzahl der Zeichen und die Gesamtzahl der in der Datei gefundenen Zeilenumbrüche ergibt. Die length()
Funktion in awk
nimmt ein Argument an, das standardmäßig length($0)
für die aktuelle ganze Zeile steht.
printf 'a\nb' | awk '{ sum+=length } END { print sum+NR }'
sollte 3, aber 4 ausgeben.
Ich mag die WC-Option selbst. Gepaart mit 'bc' können Sie Dezimalstellen an beliebig vielen Stellen eingeben.
Ich wollte ein Skript verbessern, das die Spalte "Dateigröße" eines "ls -alh" -Befehls enthielt. Ich wollte nicht nur ganzzahlige Dateigrößen, und zwei Dezimalstellen schienen zu passen. Nachdem ich diese Diskussion gelesen hatte, kam ich auf den folgenden Code.
Ich schlage vor, die Linie an den Semikolons zu brechen, wenn Sie dies in ein Skript aufnehmen.
file=$1; string=$(wc -c $file); bite=${string% *}; okay=$(echo "scale=2; $bite/1024" | bc);friend=$(echo -e "$file $okay" "kb"); echo -e "$friend"
Mein Skript heißt gpfl , für "Bilddateilänge abrufen ". Ich benutze es nach dem Mogrifizieren einer Datei in imagemagick, bevor ich ein Bild in einem GUI-JPEG-Viewer öffne oder neu lade.
Ich weiß nicht, wie dies als "Antwort" bewertet wird, da es viel von dem leiht, was bereits angeboten und diskutiert wurde. Also lasse ich es dort.
BZT
wc
den letzten Block der Datei liest, falls dies stat.st_size
nur eine Annäherung war (wie für Linux /proc
und /sys
Dateien). Ich vermute, sie haben beschlossen, den Hauptkommentar nicht komplizierter zu gestalten, als sie diese Logik ein paar Zeilen später hinzufügten
Die schnellste und einfachste Methode (IMO) ist:
bash_var=$(stat -c %s /path/to/filename)
du
und wc
Antworten beschweren , die einen Haftungsausschluss haben sollten. TUN SIE DAS NIE im wirklichen Leben. Ich habe meine Antwort heute Abend in einer realen Anwendung verwendet und fand, dass es sich lohnt, sie zu teilen. Ich denke, wir haben alle unsere Meinung zuckt mit den Schultern .