it-swarm.it

Come posso ottenere la dimensione di un file in uno script bash?

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?

271
haunted85

La tua scommessa migliore se su un 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 @ chbrown's answer per come usare stat nel terminale su Mac OS X.

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

Il problema con l'utilizzo di 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 ha un problema simile in quanto non viene specificato il formato esatto dell'output, quindi 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.

97
Nemo

Puoi anche usare il comando "Conteggio parole" (wc):

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

Il problema con 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 un linguaggio interpretato completo 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 Shell, come indicato da Gilles di seguito.

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

BSD (macOS's) 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.
  • ... la sezione FORMATI ...
  • z: la dimensione del file in byte.

Quindi tutti insieme ora:

stat -f%z myfile1.txt

NOTA: vedere @ b01's answer per come usare il comando stat su sistemi GNU/Linux. :)

53
chbrown

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. Leggerà comunque il contenuto del file (tranne se il file è un file normale o un link simbolico al file normale nella maggior parte delle implementazioni wc 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 hanno dimensioni infinite, ci vorrà un po 'di tempo. Ciò significa anche che è necessaria l'autorizzazione read per il file e il timestamp dell'ultimo accesso del file potrebbe essere aggiornato.

È standard e portatile, tuttavia si noti che alcune implementazioni wc possono includere spazi vuoti iniziali in quell'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 chiamate di sistema stat() o lstat().

Quelle riportano le informazioni trovate nell'inode. Una di queste informazioni è l'attributo st_size. Per i file regolari, questa è la dimensione del contenuto (quanti dati potrebbero essere letti da esso in assenza di errori (questo è ciò che la maggior parte delle implementazioni wc -c Usano 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'è:

  • IRIX stat (90's):

    stat -qLs -- "$file"
    

    restituisce l'attributo st_size di $file (lstat()) oppure:

    stat -s -- "$file"
    

    lo stesso tranne quando $file è un collegamento simbolico, nel qual caso è il st_size del file dopo la risoluzione del collegamento simbolico.

  • zshstat builtin (ora noto anche come zstat) nel modulo zsh/stat (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.

  • GNU stat (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 zshstat.

  • BSD stat (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 command che scaricherà tutte le informazioni stat() (non lstat(), quindi non funzionerà sui link simbolici) e con cui è possibile postelaborare, ad esempio:

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

(grazie @JeffSchaller per il aiuto per capire i dettagli ).

In tcsh:

@ size = -Z $file:q

(dimensioni dopo la risoluzione del collegamento simbolico)

Molto prima che GNU introducesse il suo comando stat, lo stesso poteva essere ottenuto con il comando GNU find con il suo -printf (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 predicato find (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 aggiungi -L per lo stesso dopo la risoluzione del collegamento simbolico. Ciò non funziona per i file del dispositivo, sebbene il 5esimo campo è il numero principale del dispositivo anziché la dimensione.

Per i dispositivi a blocchi, i sistemi in cui stat() restituisce 0 per st_size, In genere hanno altre API per segnalare la dimensione del dispositivo a blocchi. Ad esempio, Linux ha il BLKGETSIZE64ioctl() e la maggior parte delle distribuzioni Linux ora viene fornita con un comando blockdev che può farne uso:

blockdev --getsize64 -- "$device_file"

Tuttavia, è necessario disporre dell'autorizzazione in 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 modulo zsh/system):

    {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 st_size Di stat(). Alcuni (come Linux o FreeBSD) no.

Almeno su Linux, puoi usare FIONREADioctl() dopo aver aperto la pipe (in modalità read + write per evitarlo):

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 la pipe per alleviarlo ma ciò non è infallibile poiché 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 du utilizza 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).
  • 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

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

22

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
9
user150821

ls -l filename ti darà molte informazioni su un file, inclusi dimensioni del file, permessi e 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 comando stat.

8
Druckles

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.

5
Teddy

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 stat non si trova su ogni singolo sistema, puoi quasi sempre usare la soluzione AWK. Esempio; il Raspberry Pi non ha stat ma ha awk.

3
findrbot_admin

Crea piccole funzioni di utilità negli script 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.

3
oligofren

Un altro modo conforme a POSIX sarebbe usare awk con la sua funzione length() 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 sia aggiunto a sum, risultando in tal modo nel conteggio totale dei caratteri e nel numero totale di nuove righe incontrate nel file. La funzione length() in awk accetta un argomento che di default significa length($0) che è per l'intera riga corrente.

0
Inian