Hur kan jag få storleken på en fil i ett bash-skript?

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

  • stackoverflow.com/questions/5920333/how-to-check-size-of-a-file LOL för migreringen 🙂
  • Koppla ihop detta med pv och cat för ett kopieringskommando som visar framsteg och ETA 🙂
  • stat -c% s-fil. namn
  • Vid (mycket smalt) XY-problem är detta snyggt: om allt du behöver är att testa filen har en nollstorlek, har bash ett villkorligt uttryck -s så du kan helt enkelt testa om en fil har en noll längd med if [ -s file ]; then echo "file has nonzero size" ; fi

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öra stat --printf="%s" file.any | xxd - med stat -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 av du 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änder fstat, men försöker sedan att sista blocket av filen och läser de sista upp till st_blksize byte. Tydligen detta beror på att filer i Linux ’ s /proc och /sys har till exempel statstorlekar som bara är ungefärliga och wc vill rapportera den faktiska storleken, inte den statligt rapporterade storleken. Jag antar att det skulle vara konstigt för wc -c att rapportera en annan storlek än wc, 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 ignorerar echo det vita utrymmet. Något sätt att göra det konsekvent?
  • @keithpjolley: Genom att ringa fstat. Försök att köra strace 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 är st_size för filen efter symlinkupplösning.

  • zsh stat inbyggt (nu även känt som zstat) i zsh/stat -modulen (laddad med zmodload 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 BusyBox stat sedan 2 005 (kopieras från GNU stat):

    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 eller zsh 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 av zsh/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änder fstat, men läser sedan de sista upp till st_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 och stat 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. GNU du använder kibibytes istället om de inte kallas med POSIXLY_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 och wc 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 .

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *