Hur kan jag få storleken på en fil i ett bash-skript?
Hur tilldelar jag detta till en bash-variabel så att jag kan använda den senare?
Kommentarer
Svar
Din bästa satsning om du använder ett GNU-system:
stat --printf="%s" file.any
Från man stat :
% s totala storlek, i byte
I ett bash-skript:
#!/bin/bash FILENAME=/home/heiko/dummy/packages.txt FILESIZE=$(stat -c%s "$FILENAME") echo "Size of $FILENAME = $FILESIZE bytes."
OBS: se
@chbrowns svar för hur man använder stat i terminal på Mac OS X.
Kommentarer
- @ haunted85
stat
är det enklaste sättet, förutsatt att du ’ använder Linux eller Cygwin (stat
isn ’ t standard).wc -c
som föreslagen av Eug é ne är bärbar. -
stat: illegal option -- c
-
stat --printf="%s" file.txt
inte ’ t mata ut något på Debian Jessie … - På MacOS fungerar det här:
stat -f%z myfile.tar
- @woohoo Din uppmaning skriver över utdata.
man stat
säger att –printf utelämnar den efterföljande nya raden. Använd--format
eller-c
för att se utdata. Få mer insikt genom att jämförastat --printf="%s" file.any | xxd -
medstat -c "%s" file.any | xxd -
Svar
file_size_kb=`du -k "$filename" | cut -f1`
Problemet med att använda stat
är att det är ett GNU-tillägg (Linux). du -k
och cut -f1
specificeras av POSIX och är därför bärbara till alla Unix-system.
Solaris, till exempel, skickas med bash men inte med stat
. Så detta är inte helt hypotetiskt.
ls
har ett liknande problem genom att det exakta formatet på utdata inte anges, så att analysera dess utdata inte kan göras bärbart . du -h
är också en GNU-förlängning.
Håll dig till bärbara konstruktioner där det är möjligt, och du kommer att göra någons liv enklare i framtiden. Kanske din egen.
Kommentarer
-
du
ger inte ’ t filens storlek, det ger en indikation på hur mycket utrymme filen använder, vilket är subtilt annorlunda (vanligtvis är storleken som rapporteras avdu
storleken på filen avrundad upp till närmaste antal block, där ett block vanligtvis är 512B eller 1kB eller 4kB). - @ Gilles, glesa filer (dvs. filer med hål i dem) rapporterar mindre än längden.
- Detta, med
--bytes
eller-b
istället för-k
, borde vara det accepterade svaret. - @fralau: OP: n vill att ” tilldela detta till en bash-variabel så att de kan använda den senare ”, så det är mycket mer troligt att de vill ha en aktuering ett numeriskt värde, inte en läsbar ungefärlig uppskattning.
-h
är också en GNU-förlängning; det är inte standard - Att använda du med
--apparent-size
flagga returnerar en mer exakt storlek (som anges på mannen:print apparent sizes, rather than disk usage; although the apparent size is usually smaller, it may be larger due to holes in ('sparse') files, internal fragmentation, indirect blocks, and the like
)
Svar
Du kan också använda kommandot” ordräkning ”(wc
):
wc -c "$filename" | awk "{print $1}"
Problemet med wc
är att det ”lägger till filnamnet och indragar utdata. Till exempel:
$ wc -c somefile.txt 1160 somefile.txt
Om du vill undvika att kedja ett helt tolkat språk eller strömredigerare bara för att få ett antal filer, omdirigerar du bara inmatningen från filen så att wc
aldrig ser filnamnet:
wc -c < "$filename"
Det här sista formuläret kan användas med kommandosubstitution för att enkelt fånga värdet du sökte som skalvariabel, som nämnts av Gilles nedan.
size="$(wc -c <"$filename")"
Kommentarer
-
wc -c <"$FILENAME"
ger storleken utan någon annan cruft, alltsåsize=$(wc -c <"$FILENAME")
. - Bara en punkt till: Jag testade det bara och
wc -c < file
verkar vara väldigt snabb, åtminstone på OS X. I ’ jag gissar att wc har hjärnorna för att försöka statera filen om bara -c anges. - @EdwardFalk: GNU
wc -c
använderfstat
, men försöker sedan att sista blocket av filen och läser de sista upp tillst_blksize
byte. Tydligen detta beror på att filer i Linux ’ s/proc
och/sys
har till exempel statstorlekar som bara är ungefärliga ochwc
vill rapportera den faktiska storleken, inte den statligt rapporterade storleken. Jag antar att det skulle vara konstigt förwc -c
att rapportera en annan storlek änwc
, men det ’ är inte tänkt att läsa data från filen om den ’ är en normal diskfil och den ’ inte finns i minnet. Eller ännu värre, närlagringsbandlagring … - Det verkar som att
printf
fortfarande ser fördjupningen, t.ex.printf "Size: $size"
– >size: <4 spaces> 54339
. Å andra sidan ignorerarecho
det vita utrymmet. Något sätt att göra det konsekvent? - @keithpjolley: Genom att ringa
fstat
. Försök att körastrace wc -c </etc/passwd
så kan du se vad den gör.
Svar
BSD ”s (macOS” s) stat
har argumentflagga med olika format och olika fältspecifikationer. Från man stat(1)
:
-
-f format
: Visa information med det angivna formatet. Se avsnittet FORMATER för en beskrivning av giltiga format. - … avsnittet FORMATER …
-
z
: Storleken på fil i byte.
Så allt tillsammans nu:
stat -f%z myfile1.txt
OBS: se @ b01 ”svar för hur man använder kommandot stat
på GNU / Linux-system. 🙂
Kommentarer
- Observera att detta endast är en BSD-lösning. Det fungerar inte ’ med GNU
stat
tyvärr.
Svar
Beror på vad du menar med storlek .
size=$(wc -c < "$file")
ger dig antalet byte som kan läsas från filen. IOW, den är storleken på filens innehåll. Den läser dock innehållet i filen (förutom om filen är en vanlig fil eller symlänk till vanlig fil i de flesta wc
-implementeringar som en optimering). Det kan ha biverkningar. Till exempel, för ett namngivet rör kan det som har lästs inte längre läsas igen och för saker som /dev/zero
eller /dev/random
som är av oändlig storlek, det tar ett tag. Det betyder också att du behöver read
behörighet för filen, och sista åtkomsttidstämpel för filen kan uppdateras.
Det är standard och bärbart, men observera att vissa wc
-implementeringar kan inkludera ledande blanksteg i den utgången. Ett sätt att bli av med dem är att använda:
size=$(($(wc -c < "$file")))
eller att undvika ett fel om ett tomt aritmetiskt uttryck i dash
eller yash
när wc
ger ingen utdata (som när filen inte kan öppnas):
size=$(($(wc -c < "$file") +0))
ksh93
har wc
inbyggt (förutsatt att du aktiverar det kan du också åberopa det som command /opt/ast/bin/wc
) vilket gör det mest effektivt för vanliga filer i det skalet.
Olika system har ett kommando som heter stat
som ”är ett gränssnitt till stat()
eller lstat()
systemanrop.
Den rapportinformation som finns i inode. En av den informationen är attributet st_size
. För vanliga filer är det storleken på innehållet (hur mycket data kan läsas från det i avsaknad av fel (det är vad de flesta wc -c
-implementationer använder för att optimera dem) ). För symlänkar är det ”storleken i byte på målvägen. För namngivna rör, beroende på system, är det antingen 0 eller antalet byte som för närvarande finns i rörbufferten. Samma för blockeringsenheter där du, beroende på system, får 0 eller storleken i byte på den underliggande lagringen.
Du behöver inte läsbehörighet till filen för att få den informationen, bara sökbehörighet till katalog det är länkat till.
I kronologisk ordning finns:
-
IRIX
stat
(90 ”s):stat -qLs -- "$file"
returnerar
st_size
attribut för$file
(lstat()
) eller:stat -s -- "$file"
samma förutom när
$file
är en symlänk i vilket fall det ärst_size
för filen efter symlinkupplösning. -
zsh
stat
inbyggt (nu även känt somzstat
) izsh/stat
-modulen (laddad medzmodload zsh/stat
) (1997):stat -L +size -- $file # st_size of file stat +size -- $file # after symlink resolution
eller för att lagra i en variabel:
stat -L -A size +size -- $file
uppenbarligen, det är det mest effektiva i det skalet.
-
GNU
stat
(2001); även i BusyBoxstat
sedan 2 005 (kopieras från GNUstat
):stat -c %s -- "$file" # st_size of file stat -Lc %s -- "$file" # after symlink resolution
(notera betydelsen av
-L
är omvänd jämfört med IRIX ellerzsh
stat
. -
BSD: s
stat
(2002):stat -f %z -- "$file" # st_size of file stat -Lf %z -- "$file" # after symlink resolution
Eller så kan du använda stat()
/ lstat()
-funktionen för något skriptspråk som perl
:
perl -le "print((lstat shift)[7])" -- "$file"
AIX har också en istat
-kommando som kommer att dumpa alla stat()
(inte lstat()
, så vi kommer inte att arbeta med symlänkar ) information och som du kan efterbearbeta med, till exempel:
LC_ALL=C istat "$file" | awk "NR == 4 {print $5}"
(tack @JeffSchaller för hjälp med att räkna ut detaljerna ).
I tcsh
:
@ size = -Z $file:q
(storlek efter symlinkupplösning)
Långt innan GNU introducerade kommandot stat
kunde samma uppnås med GNU find
kommando med dess -printf
predikat (redan 1991):
find -- "$file" -prune -printf "%s\n" # st_size of file find -L -- "$file" -prune -printf "%s\n" # after symlink resolution
En fråga är dock att det inte är fungera om $file
börjar med -
eller är ett find
predikat (som !
, (
…).
Standardkommandot för att få stat()
/ lstat()
informationen är ls
.
POSIX, du kan göra:
LC_ALL=C ls -dn -- "$file" | awk "{print $5; exit}"
och lägg till -L
för samma efter symlinkupplösning. Det fungerar inte för enhetsfiler men där 5 th -fältet är enhetens huvudnummer istället för storleken.
För blockenheter, system där stat()
returnerar 0 för st_size
, har vanligtvis andra API: er för att rapportera storleken på blockenheten. Linux har till exempel BLKGETSIZE64
ioctl()
, och de flesta Linux-distributioner levereras nu med ett blockdev
-kommando som kan använda det:
blockdev --getsize64 -- "$device_file"
Du behöver dock läsbehörighet till enhetsfilen för det. Det är vanligtvis möjligt att härleda storleken på annat sätt. Till exempel (fortfarande på Linux):
lsblk -bdno size -- "$device_file"
Bör fungera utom tomma enheter.
En metod som fungerar för alla sökbara filer (så inkluderar vanliga filer, de flesta blockeringsenheter och vissa teckenenheter) är att öppna filen och söka till slutet:
-
Med
zsh
(efter laddning avzsh/system
-modulen):{sysseek -w end 0 && size=$((systell(0)))} < $file
-
Med
ksh93
:< "$file" <#((size=EOF))
eller
{ size=$(<#((EOF))); } < "$file"
-
med
perl
:perl -le "seek STDIN, 0, 2 or die "seek: $!"; print tell STDIN" < "$file"
För namngivna rör har vi sett att vissa system (AIX, Solaris, HP / UX åtminstone) gör mängden data i rörbufferten tillgänglig i stat()
”s st_size
. Vissa (som Linux eller FreeBSD) gör inte det.
Åtminstone på Linux kan du använda FIONREAD
ioctl()
efter att ha öppnat röret (i läs + skrivläge för att undvika att det hänger):
fuser -s -- "$fifo_file" && perl -le "require "sys/ioctl.ph"; ioctl(STDIN, &FIONREAD, $n) or die$!; print unpack "L", $n" <> "$fifo_file"
Observera att medan det inte ”t läser rörets innehåll kan bara öppningen av det namngivna röret fortfarande ha biverkningar. Vi använder fuser
för att först kontrollera att någon process redan har röret öppet för att lindra det men att det inte är idiotsäkert som fuser
inte kunna kontrollera alla processer.
Hittills har vi bara övervägt storleken på primära data som är associerade med filerna.Det tar inte hänsyn till storleken på metadata och all supportinfrastruktur som behövs för att lagra filen.
Ett annat inodattribut som returneras av stat()
är st_blocks
. Det är antalet 512 byteblock som används för att lagra filens data (och ibland några av dess metadata som de utökade attributen på ext4-filsystem på Linux). ”t inkludera själva inoden, eller posterna i katalogerna som filen är länkad till.
Storlek och diskanvändning är inte nödvändigtvis tätt relaterade eftersom komprimering, sparshet (ibland vissa metadata), extra infrastruktur som indirekt block i vissa filsystem har inflytande på det senare.
Det är vanligtvis vad du
använder för att rapportera diskanvändning. De flesta av kommandona som listas ovan kommer att kunna få den informationen.
-
POSIXLY_CORRECT=1 ls -sd -- "$file" | awk "{print $1; exit}"
-
POSIXLY_CORRECT=1 du -s -- "$file"
(inte för kataloger där det skulle inkludera disk usag e av filerna inom). - 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"
Kommentarer
- klart det mest omfattande och informativa svaret. tack. jag kan använda detta för att skapa basplattformar över flera plattformar med BSD- och GNU-statistikinformation
- Roligt faktum: GNU-kärnverktyg
wc -c
använderfstat
, men läser sedan de sista upp tillst_blksize
byte. Tydligen detta beror på att filer i Linux ’ s/proc
och/sys
har till exempel statstorlekar som bara är ungefärliga . Detta är bra för korrekthet, men dåligt om slutet på filen finns på hårddisken och inte i minnet (särskilt om den används på många filer i en loop). Och väldigt dåligt om filen migreras till tejplagring nära linjen , eller t.ex. ett FUSE transparent-dekompression-filsystem. - skulle inte heller detta arbete
ls -go file | awk '{print $3}'
- @StevenPenny de
-go
skulle vara SysV-enheterna, de skulle ’ inte arbeta med BSD: er (valfritt (XSI) i POSIX). Du ’ d behöver ocksåls -god file | awk '{print $3; exit}'
(-d
för att det ska fungera i kataloger,exit
för symlänkar med nya rader i målet). Problemen med enhetsfiler kvarstår också. - @ αғsнιη Unix API skiljer inte mellan text och binära filer. Det ’ är alla sekvenser av byte. Vissa applikationer kanske vill tolka dessa byte som text men uppenbarligen inte
wc -c
som rapporterar antalet byte.
Svar
Detta skript kombinerar många sätt att beräkna filstorlek:
( 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}"
Skriptet fungerar på många Unix-system inklusive Linux, BSD, OSX, Solaris, SunOS, etc.
Filstorleken visar antalet byte. Det är den uppenbara storleken, vilket är de byte filen använder på en typisk disk, utan speciell komprimering, eller speciella glesa områden, eller odelade block etc.
Detta skript har en produktionsversion med mer hjälp och fler alternativ här: https://github.com/SixArm/file-size
Svar
stat verkar göra det med de färsta systemanropen:
$ 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
Svar
ls -l filename
ger dig mycket information om en fil, inklusive filstorlek, behörigheter och ägare.
Filstorleken i den femte kolumnen och visas i byte. I exemplet nedan är filstorleken knappt 2 KB:
-rw-r--r-- 1 user owner 1985 2011-07-12 16:48 index.php
Redigera: Detta är tydligen inte lika tillförlitligt som kommandot stat
.
Kommentarer
- Jag tror att både
ls -l
ochstat
kommandot ger tillförlitlig storleksinformation. Jag hittade ingen hänvisning till det motsatta.ls -s
ger storlek i antal block. - @ dabest1 det ’ är inte tillförlitligt på ett sätt som en annan unix, deras output kan vara annorlunda (och i vissa unix är det).
- Ja, IIRC, Solaris visade inte ’ t gruppnamnet som standard, vilket leder till färre kolumner i utdata.
- Eftersom storleken är ren numerisk, omgiven av blanksteg, och datumåret är rent numeriskt, i ett definierat format, skulle det vara möjligt att använda en regexp för att behandla användare + ägare som ett fält, oavsett om gruppen var närvarande eller inte. (en övning för läsaren!)
Svar
du filename
kommer att berätta för dig diskanvändning i byte.
Jag föredrar du -h filename
, vilket ger dig storleken i ett läsbart format.
Kommentarer
- det eller
stat -c "%s"
😉 - Denna smak av
du
skriver ut storlek i block av 1024 byte, inte ett enkelt antal byte. - Observera att standard
du
ger en utdata i antal 512 byte-enheter. GNUdu
använder kibibytes istället om de inte kallas medPOSIXLY_CORRECT
i sin miljö. - För filer av typen katalog , som ger diskanvändningen av katalogen men också av alla andra filer inom (rekursivt).
Svar
Skapa små verktygsfunktioner i dina skalskript som du kan delegera till.
Exempel
#! /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
Baserat på information från @ Stéphane Chazelas ”svar.
Kommentarer
- Se även
gzip -v < file > /dev/null
för att kontrollera komprimerbarheten för en fil. - @St é phaneChazelas är inte säker på om jag tycker att det var en förbättring. dessa ärenden kan enkelt avskräcka noobs; jag kommer säkert aldrig ihåg hur man får rätt 🙂 är falluttalanden i sig mer bärbara eftersom såg jag poängen när det finns fler än två fall, men annars … +
- Jag antar att det ’ också är en fråga om smak, men här är det ’ det typiska fallet där du ’ vill använda en
case
uttalande.case
är Bourne / POSIX-konstruktionen för att göra mönstermatchning.[[...]]
är endast ksh / bash / zsh (med variationer).
Svar
Jag hittade en AWK 1 liner, och den hade ett fel men jag fixade det. Jag lade också till i PetaBytes efter 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] }")
Med tanke på stat finns inte i varje enskilt system, du kan nästan alltid använda AWK-lösningen. Exempel; Raspberry Pi har inte stat men det har awk .
Kommentarer
- Helt INTE vad OP frågade, men trevligt litet arbete.
Svar
Jag gillar wc-alternativet själv. Parat med ”bc” kan du få decimaler till så många platser som du vill.
Jag ville förbättra ett skript som jag hade som kände ”redigerade kolumnen” filstorlek ”i en” ls – alh ”kommando. Jag ville inte bara heltalsfilstorlekar, och två decimaler tycktes passa, så efter att ha läst den här diskussionen kom jag med koden nedan.
Jag föreslår att du bryter raden vid semikolon om du inkluderar detta i ett skript.
file=$1; string=$(wc -c $file); bite=${string% *}; okay=$(echo "scale=2; $bite/1024" | bc);friend=$(echo -e "$file $okay" "kb"); echo -e "$friend"
Mitt skript kallas gpfl , för ”få längd på bildfil.” Jag använder den efter att ha gjort en mogrify på en fil i imagemagick innan jag öppnade eller laddade om en bild i en GUI jpeg-visare.
Jag vet inte hur detta ser ut som ett ”svar”, eftersom det lånar mycket från det som redan erbjudits och diskuterats. Så jag lämnar den där.
BZT
Kommentarer
- Jag föredrar att använda ” stat ” eller ” ls ” div Jag brukar ’ inte gillar att använda ” wc ” för att få filstorlekar eftersom det läser fysiskt hela filen. Om du har många filer eller särskilt stora filer kan det ta mycket tid. Men din lösning är kreativ … + 1.
- Jag håller med uppfattningen att använda ” stat ” över ” wc ” för filstorlek, men om du använder ” wc -c ” kommer ingen data att läsas; istället används lseek för att räkna ut antalet byte i en fil. lingrok.org/xref/coreutils/src/wc.c#228
- @ bbaja42 : notera att GNU Coreutils läser inte det sista blocket i filen, om
stat.st_size
bara var en approximation (som för Linux/proc
och/sys
filer). Jag antar att de bestämde sig för att inte göra huvudkommentaren mer komplicerad när de lade till den logiken ett par rader nedåt: lingrok.org/xref/coreutils/src/wc.c#246
Svar
Snabbaste och enklaste (IMO) metoden är:
bash_var=$(stat -c %s /path/to/filename)
Kommentarer
- Rösta sedan upp ett eller flera av de befintliga svaren som nämner stat; inget behov av att upprepa det igen …
- @JeffSchaller Jag har just röstat på Stephane ’ svar på dina instruktioner.Jag tycker att det är för komplicerat för mina syften. Därför skickade jag detta enkla svar för likasinnade själar.
- Tack; det ’ är bara att en sjätte instans av en ” stat ” svar förenklar inte ’ t detta Q & A, men skulle hellre få en ny läsare att fråga sig ” hur skiljer sig detta svar från de andra? ” och leder till mer förvirring istället för mindre.
- @JeffSchaller antar jag. Men jag kunde klaga på de många
du
ochwc
svar som borde ha en ansvarsfriskrivning GÖR ALDRIG DETTA i verkligheten liv. Jag använde mitt svar i en verklig applikation ikväll och tyckte att det var värt att dela. Jag antar att vi alla har våra åsikter rycker på axlarna .
pv
ochcat
för ett kopieringskommando som visar framsteg och ETA 🙂-s
så du kan helt enkelt testa om en fil har en noll längd medif [ -s file ]; then echo "file has nonzero size" ; fi