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 (statisn ’ t standard).wc -csom föreslagen av Eug é ne är bärbar. -
stat: illegal option -- c -
stat --printf="%s" file.txtinte ’ 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 statsäger att –printf utelämnar den efterföljande nya raden. Använd--formateller-cfö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
-
duger inte ’ t filens storlek, det ger en indikation på hur mycket utrymme filen använder, vilket är subtilt annorlunda (vanligtvis är storleken som rapporteras avdustorleken 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
--byteseller-bistä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-sizeflagga 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 < fileverkar 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 -canvänderfstat, men försöker sedan att sista blocket av filen och läser de sista upp tillst_blksizebyte. Tydligen detta beror på att filer i Linux ’ s/prococh/syshar till exempel statstorlekar som bara är ungefärliga ochwcvill rapportera den faktiska storleken, inte den statligt rapporterade storleken. Jag antar att det skulle vara konstigt förwc -catt 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
printffortfarande ser fördjupningen, t.ex.printf "Size: $size"– >size: <4 spaces> 54339. Å andra sidan ignorerarechodet 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/passwdså 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
stattyvä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_sizeattribut för$file(lstat()) eller:stat -s -- "$file"samma förutom när
$fileär en symlänk i vilket fall det ärst_sizeför filen efter symlinkupplösning. -
zshstatinbyggt (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 resolutioneller för att lagra i en variabel:
stat -L -A size +size -- $fileuppenbarligen, det är det mest effektiva i det skalet.
-
GNU
stat(2001); även i BusyBoxstatsedan 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 ellerzshstat. -
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 -canvänderfstat, men läser sedan de sista upp tillst_blksizebyte. Tydligen detta beror på att filer i Linux ’ s/prococh/syshar 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
-goskulle 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}'(-dför att det ska fungera i kataloger,exitfö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 -csom 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 -lochstatkommandot ger tillförlitlig storleksinformation. Jag hittade ingen hänvisning till det motsatta.ls -sger 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
duskriver ut storlek i block av 1024 byte, inte ett enkelt antal byte. - Observera att standard
duger en utdata i antal 512 byte-enheter. GNUduanvänder kibibytes istället om de inte kallas medPOSIXLY_CORRECTi 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/nullfö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
caseuttalande.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_sizebara var en approximation (som för Linux/prococh/sysfiler). 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
duochwcsvar 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 .
pvochcatför ett kopieringskommando som visar framsteg och ETA 🙂-sså du kan helt enkelt testa om en fil har en noll längd medif [ -s file ]; then echo "file has nonzero size" ; fi