Come posso ottenere la dimensione di un file in uno script bash?
Come posso assegnarlo a una variabile bash in modo da poterlo utilizzare in seguito?
pv
e cat
per un comando di copia che mostra lo stato di avanzamento e l'ETA :)
Come posso ottenere la dimensione di un file in uno script bash?
Come posso assegnarlo a una variabile bash in modo da poterlo utilizzare in seguito?
pv
e cat
per un comando di copia che mostra lo stato di avanzamento e l'ETA :)
Risposte:
La tua scommessa migliore se su un sistema GNU:
stat --printf="%s" file.any
Da man stat :
% s dimensione totale, in byte
In uno script bash:
#!/bin/bash
FILENAME=/home/heiko/dummy/packages.txt
FILESIZE=$(stat -c%s "$FILENAME")
echo "Size of $FILENAME = $FILESIZE bytes."
NOTA: vedi la risposta di @ chbrown per come utilizzare stat nel terminale su Mac OS X.
stat
è il modo più semplice, supponendo che tu stia usando Linux o Cygwin ( stat
non è standard). wc -c
come suggerito da Eugéne è portatile.
stat: illegal option -- c
stat --printf="%s" file.txt
non produce nulla su Debian Jessie ...
stat -f%z myfile.tar
man stat
dice che --printf omette la nuova riga finale. Utilizzare --format
o -c
per vedere l'output. Ottieni maggiori informazioni comparando stat --printf="%s" file.any | xxd -
astat -c "%s" file.any | xxd -
file_size_kb=`du -k "$filename" | cut -f1`
Il problema con l'utilizzo stat
è che si tratta di un'estensione GNU (Linux). du -k
e cut -f1
sono specificati da POSIX e sono quindi portabili su qualsiasi sistema Unix.
Solaris, ad esempio, viene fornito con bash ma non con stat
. Quindi questo non è del tutto ipotetico.
ls
presenta un problema simile in quanto non viene specificato il formato esatto dell'output, pertanto l'analisi del suo output non può essere eseguita in modo portabile. du -h
è anche un'estensione GNU.
Attenersi ai costrutti portatili, ove possibile, e semplificherete la vita di qualcuno in futuro. Forse il tuo.
du
non fornisce le dimensioni del file, fornisce un'indicazione di quanto spazio utilizza il file, che è leggermente diverso (di solito la dimensione indicata da du
è la dimensione del file arrotondata per eccesso al numero più vicino di blocchi, dove un blocco è in genere 512B o 1kB o 4kB).
--bytes
o -b
invece di -k
, dovrebbe essere la risposta accettata.
-h
opzione ("umana")du
produrrà la risposta più appropriata per i casi generali:, file_size=`du -h "$filename" | cut -f1
poiché visualizzerà K (kilobyte), M (Megabyte) o G (Gigabyte) come appropriato.
Puoi anche usare il comando "conteggio parole" ( wc
):
wc -c "$filename" | awk '{print $1}'
Il problema wc
è che aggiungerà il nome file e indenterà l'output. Per esempio:
$ wc -c somefile.txt
1160 somefile.txt
Se desideri evitare il concatenamento di una lingua completamente interpretata o di un editor di stream solo per ottenere un conteggio delle dimensioni del file, reindirizza l'input dal file in modo che wc
non veda mai il nome del file:
wc -c < "$filename"
Quest'ultimo modulo può essere usato con la sostituzione dei comandi per afferrare facilmente il valore che stavi cercando come variabile di shell, come menzionato da Gilles di seguito.
size="$(wc -c <"$filename")"
wc -c <"$FILENAME"
dà le dimensioni senza nessun'innesto, quindi size=$(wc -c <"$FILENAME")
.
wc -c < file
sembra essere molto veloce, almeno su OS X. Immagino che wc abbia il cervello per provare a stat il file se viene specificato solo -c.
wc -c
utilizza GNU fstat
, ma cerca il penultimo blocco del file e legge gli ultimi st_blksize
byte fino a . Apparentemente ciò è dovuto al fatto che i file in Linux /proc
e, /sys
ad esempio, hanno dimensioni stat solo approssimative e wc
vogliono riportare la dimensione effettiva, non la dimensione riportata dalle statistiche. Immagino che sarebbe strano wc -c
riportare una dimensione diversa da quella wc
, ma non è idea leggere i dati dal file se è un normale file su disco e non è in memoria. O peggio, archiviazione su nastro near-line ...
printf
veda ancora il rientro, ad es. printf "Size: $size"
-> size: <4 spaces> 54339
. D'altra parte echo
ignora lo spazio bianco. Un modo per renderlo coerente?
fstat
. Prova a correre strace wc -c </etc/passwd
e puoi vedere cosa sta facendo.
BSD (Mac OS X) stat
ha un flag di argomento di formato diverso e diversi identificatori di campo. Da man stat(1)
:
-f format
: Visualizza le informazioni utilizzando il formato specificato. Vedi la sezione FORMATI per una descrizione dei formati validi.z
: La dimensione del file in byte.Quindi tutti insieme ora:
stat -f%z myfile1.txt
Dipende da cosa intendi per dimensione .
size=$(wc -c < "$file")
ti darà il numero di byte che possono essere letti dal file. IOW, è la dimensione del contenuto del file. Tuttavia leggerà il contenuto del file (tranne se il file è un file normale o un link simbolico al file normale nella maggior parte delle wc
implementazioni come ottimizzazione). Ciò potrebbe avere effetti collaterali. Ad esempio, per una pipe denominata, ciò che è stato letto non può più essere letto di nuovo e per cose come /dev/zero
o /dev/random
che sono di dimensioni infinite, ci vorrà del tempo. Ciò significa anche che è necessaria l' read
autorizzazione per il file e potrebbe essere aggiornato l' ultimo timestamp di accesso al file.
È standard e portatile, tuttavia si noti che alcune wc
implementazioni possono includere spazi vuoti iniziali in tale output. Un modo per sbarazzarsi di loro è usare:
size=$(($(wc -c < "$file")))
o per evitare un errore su un'espressione aritmetica vuota in dash
o yash
quando wc
non produce alcun output (come quando il file non può essere aperto):
size=$(($(wc -c < "$file") +0))
ksh93
ha wc
incorporato (purché tu lo abiliti, puoi anche invocarlo come command /opt/ast/bin/wc
) che lo rende il più efficiente per i file regolari in quella shell.
Vari sistemi hanno un comando chiamato stat
che è un'interfaccia per le stat()
o lstat()
chiamate di sistema.
Quelle riportano le informazioni trovate nell'inode. Una di queste informazioni è l' st_size
attributo. Per i file regolari, questa è la dimensione del contenuto (quanti dati possono essere letti da esso in assenza di errori (questo è ciò che la maggior parte delle wc -c
implementazioni utilizza nella loro ottimizzazione)). Per i collegamenti simbolici, questa è la dimensione in byte del percorso target. Per le pipe con nome, a seconda del sistema, è 0 o il numero di byte attualmente nel buffer delle pipe. Lo stesso vale per i dispositivi a blocchi in cui, a seconda del sistema, si ottiene 0 o la dimensione in byte della memoria sottostante.
Non è necessario il permesso di lettura del file per ottenere tali informazioni, solo il permesso di ricerca nella directory a cui è collegato.
Per ordine cronologico, c'è:
IRIXstat
(anni '90):
stat -qLs -- "$file"
restituisce l' st_size
attributo di $file
( lstat()
) o:
stat -s -- "$file"
lo stesso tranne quando $file
è un collegamento simbolico nel qual caso è st_size
il file dopo la risoluzione del collegamento simbolico.
zsh
stat
builtin (ora noto anche come zstat
) nel zsh/stat
modulo (caricato con zmodload zsh/stat
) (1997):
stat -L +size -- $file # st_size of file
stat +size -- $file # after symlink resolution
o per memorizzare in una variabile:
stat -L -A size +size -- $file
ovviamente, questo è il più efficiente in quella shell.
GNUstat
(2001); anche in BusyBox stat
dal 2005 (copiato da GNU stat
):
stat -c %s -- "$file" # st_size of file
stat -Lc %s -- "$file" # after symlink resolution
(notare che il significato di -L
è invertito rispetto a IRIX o zsh
stat
.
BSDstat
(2002):
stat -f %z -- "$file" # st_size of file
stat -Lf %z -- "$file" # after symlink resolution
Oppure puoi usare la funzione stat()
/ lstat()
di alcuni linguaggi di scripting come perl
:
perl -le 'print((lstat shift)[7])' -- "$file"
AIX ha anche un istat
comando che scaricherà tutte le informazioni stat()
(no lstat()
, quindi non funzionerà sui collegamenti simbolici) e con le quali potresti post-processarle, ad esempio:
LC_ALL=C istat "$file" | awk 'NR == 4 {print $5}'
(grazie @JeffSchaller per l' aiuto nella comprensione dei dettagli ).
In tcsh
:
@ size = -Z $file:q
(dimensioni dopo la risoluzione del collegamento simbolico)
Molto prima che GNU introducesse il suo stat
comando, lo stesso poteva essere ottenuto con il find
comando GNU con il suo -printf
predicato (già nel 1991):
find -- "$file" -prune -printf '%s\n' # st_size of file
find -L -- "$file" -prune -printf '%s\n' # after symlink resolution
Un problema però è che non funziona se $file
inizia con -
o è un find
predicato (come !
, (
...).
Il comando standard per ottenere le informazioni stat()
/ lstat()
è ls
.
POSIXly, puoi fare:
LC_ALL=C ls -dn -- "$file" | awk '{print $5; exit}'
e aggiungere -L
per lo stesso dopo la risoluzione del collegamento simbolico. Ciò non funziona per i file di dispositivo, sebbene il 5 ° campo sia il numero maggiore del dispositivo anziché la dimensione.
Per i dispositivi a blocchi, i sistemi in cui stat()
restituisce 0 per st_size
, di solito hanno altre API per segnalare la dimensione del dispositivo a blocchi. Ad esempio, Linux ha BLKGETSIZE64
ioctl()
, e la maggior parte delle distribuzioni Linux ora viene fornita con un blockdev
comando che può farne uso:
blockdev --getsize64 -- "$device_file"
Tuttavia, è necessario disporre dell'autorizzazione di lettura per il file del dispositivo. Di solito è possibile ricavare la dimensione con altri mezzi. Ad esempio (ancora su Linux):
lsblk -bdno size -- "$device_file"
Dovrebbe funzionare ad eccezione dei dispositivi vuoti.
Un approccio che funziona per tutti i file ricercabili (quindi include file regolari, la maggior parte dei dispositivi a blocchi e alcuni dispositivi a caratteri) è quello di aprire il file e cercare fino alla fine:
Con zsh
(dopo aver caricato il zsh/system
modulo):
{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"
Per le pipe con nome, abbiamo visto che alcuni sistemi (almeno AIX, Solaris, HP / UX) rendono disponibile la quantità di dati nel buffer delle pipe in stat()
's st_size
. Alcuni (come Linux o FreeBSD) no.
Almeno su Linux, puoi usare il FIONREAD
ioctl()
dopo aver aperto la pipe (in modalità lettura + scrittura per evitare che si blocchi):
fuser -s -- "$fifo_file" &&
perl -le 'require "sys/ioctl.ph";
ioctl(STDIN, &FIONREAD, $n) or die$!;
print unpack "L", $n' <> "$fifo_file"
Tuttavia, nota che mentre non legge il contenuto della pipa, la semplice apertura della pipa denominata qui può comunque avere effetti collaterali. Stiamo usando fuser
per verificare innanzitutto che alcuni processi abbiano già aperto il tubo per alleviarlo, ma questo non è infallibile in quanto fuser
potrebbe non essere in grado di controllare tutti i processi.
Ora, finora abbiamo considerato solo la dimensione dei dati primari associati ai file. Ciò non tiene conto delle dimensioni dei metadati e di tutte le infrastrutture di supporto necessarie per archiviare quel file.
Un altro attributo inode restituito da stat()
è st_blocks
. Questo è il numero di blocchi da 512 byte utilizzati per archiviare i dati del file (e talvolta alcuni dei suoi metadati come gli attributi estesi su filesystem ext4 su Linux). Ciò non include l'inode stesso o le voci nelle directory a cui è collegato il file.
Le dimensioni e l'utilizzo del disco non sono necessariamente strettamente correlati come compressione, scarsità (a volte alcuni metadati), infrastrutture extra come blocchi indiretti in alcuni filesystem hanno un'influenza su quest'ultimo.
Questo è in genere ciò che viene du
utilizzato per segnalare l'utilizzo del disco. La maggior parte dei comandi sopra elencati sarà in grado di ottenere tali informazioni.
POSIXLY_CORRECT=1 ls -sd -- "$file" | awk '{print $1; exit}'
POSIXLY_CORRECT=1 du -s -- "$file"
(non per le directory in cui ciò includerebbe l'utilizzo del disco dei file all'interno).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
usa fstat
, ma poi legge gli ultimi st_blksize
byte fino a . Apparentemente ciò è dovuto al fatto che i file in Linux /proc
e, /sys
ad esempio, hanno dimensioni stat solo approssimative . Questo è utile per la correttezza, ma male se la fine del file è su disco e non in memoria (specialmente se usata su molti file in un ciclo). E molto male se il file viene migrato su un archivio su nastro near-line o, ad esempio, un filesystem a decompressione trasparente FUSE.
ls -go file | awk '{print $3}'
-go
sarebbero quelli SysV, non funzionerebbero su BSD (opzionale (XSI) in POSIX). Avresti anche bisogno ls -god file | awk '{print $3; exit}'
( -d
affinché funzioni su directory, exit
per collegamenti simbolici con le nuove righe nel target). Restano anche i problemi con i file del dispositivo.
wc -c
riportano il numero di byte.
Questo script combina molti modi per calcolare la dimensione del file:
(
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}'
Lo script funziona su molti sistemi Unix tra cui Linux, BSD, OSX, Solaris, SunOS, ecc.
La dimensione del file mostra il numero di byte. È la dimensione apparente, ovvero i byte che il file utilizza su un disco tipico, senza compressione speciale, aree speciali sparse, blocchi non allocati, ecc.
Questo script ha una versione di produzione con più aiuto e più opzioni qui: https://github.com/SixArm/file-size
stat sembra farlo con il minor numero di chiamate di 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
ls -l filename
ti fornirà molte informazioni su un file, incluse le dimensioni del file, le autorizzazioni e il proprietario.
La dimensione del file nella quinta colonna e viene visualizzata in byte. Nell'esempio seguente, la dimensione del file è appena inferiore a 2 KB:
-rw-r--r-- 1 user owner 1985 2011-07-12 16:48 index.php
Modifica: apparentemente non è affidabile come il stat
comando.
ls -l
e il stat
comando forniscano informazioni sulle dimensioni affidabili. Non ho trovato alcun riferimento al contrario. ls -s
darà dimensioni in numero di blocchi.
du filename
ti dirà l'utilizzo del disco in byte.
Preferisco du -h filename
, che ti dà le dimensioni in un formato leggibile dall'uomo.
du
stampa stampa la dimensione in blocchi di 1024 byte, non un semplice conteggio di byte.
du
fornisce un'uscita in numero di unità da 512 byte. GNU du
usa invece i kibibyte a meno che non sia chiamato con POSIXLY_CORRECT
nel suo ambiente.
Crea piccole funzioni di utilità negli script della shell a cui puoi delegare.
Esempio
#! /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
Sulla base di informazioni fornite dalla risposta di @ Stéphane Chazelas.
gzip -v < file > /dev/null
per verificare la compressibilità di un file.
case
dichiarazione. case
è il costrutto Bourne / POSIX per eseguire la corrispondenza dei modelli. [[...]]
è solo ksh / bash / zsh (con variazioni).
Ho trovato un Liner AWK 1 e aveva un bug ma l'ho risolto. Ho anche aggiunto PetaBytes dopo 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] }')
Considerando che stat non è presente su ogni singolo sistema, è quasi sempre possibile utilizzare la soluzione AWK. Esempio; il Raspberry Pi non ha stat ma ha awk .
Un altro modo conforme a POSIX sarebbe utilizzare awk
con la sua length()
funzione che restituisce la lunghezza, in caratteri su ciascuna riga del file di input, esclusi i caratteri di nuova riga. Così facendo
awk '{ sum+=length } END { print sum+NR }' file
ci assicuriamo che NR
venga aggiunto sum
, risultando quindi nel conteggio totale dei caratteri e nel numero totale di nuove righe incontrate nel file. La length()
funzione in awk
accetta un argomento che per impostazione predefinita significa length($0)
che è per l'intera riga corrente.
printf 'a\nb' | awk '{ sum+=length } END { print sum+NR }'
dovrebbe stampare 3 ma stampare 4.
Mi piace anche l'opzione WC. Abbinato a "bc", puoi ottenere decimali in tutti i posti che desideri.
Stavo cercando di migliorare uno script che avevo strappato fuori dalla colonna 'dimensione file' di un comando 'ls -alh'. Non volevo solo dimensioni di file interi e due decimali sembravano adattarsi, quindi dopo aver letto questa discussione, ho trovato il codice qui sotto.
Suggerisco di spezzare la linea al punto e virgola se includi questo in uno script.
file=$1; string=$(wc -c $file); bite=${string% *}; okay=$(echo "scale=2; $bite/1024" | bc);friend=$(echo -e "$file $okay" "kb"); echo -e "$friend"
Il mio script si chiama gpfl , per "ottenere la lunghezza del file di immagine". Lo uso dopo aver fatto un mogrify su un file in imagemagick, prima di aprire o ricaricare un'immagine in un visualizzatore jpeg GUI.
Non so come questa sia una "risposta", poiché prende in prestito molto da ciò che è già stato offerto e discusso. Quindi lo lascerò lì.
BZT
wc
legge l'ultimo blocco del file, nel caso stat.st_size
fosse solo un'approssimazione (come per Linux /proc
e i /sys
file). Immagino che abbiano deciso di non rendere il commento principale più complicato quando hanno aggiunto quella logica un paio di righe: lingrok.org/xref/coreutils/src/wc.c#246
Il metodo più rapido e semplice (IMO) è:
bash_var=$(stat -c %s /path/to/filename)
du
e delle wc
risposte che dovrebbero avere una dichiarazione di non responsabilità MAI FARE QUESTO nella vita reale. Stasera ho usato la mia risposta in un'applicazione reale e ho pensato che valesse la pena condividerla. Immagino che tutti noi abbiamo le nostre opinioni scrollate di spalle .