Bagaimana cara memeriksa ukuran file menggunakan Bash?

145

Saya punya skrip yang memeriksa ukuran 0, tapi saya pikir pasti ada cara yang lebih mudah untuk memeriksa ukuran file. Yaitu file.txtbiasanya 100rb; cara membuat skrip memeriksa apakah kurang dari 90k (termasuk 0), dan membuatnya mendapatkan salinan baru karena file rusak dalam kasus ini.

Apa yang saya gunakan saat ini ..

if [ -n file.txt ]
then
 echo "everything is good"
else
 mail -s "file.txt size is zero, please fix. " myemail@gmail.com < /dev/null
 # Grab wget as a fallback 
 wget -c https://www.server.org/file.txt -P /root/tmp --output-document=/root/tmp/file.txt
 mv -f /root/tmp/file.txt /var/www/file.txt
fi
pengguna349418
sumber
1
unix.stackexchange.com/questions/16640/…
Ciro Santilli 郝海东 冠状 病 六四 六四 事件 法轮功

Jawaban:

250

[ -n file.txt ]tidak memeriksa ukurannya, memeriksa string file.txtyang panjangnya tidak nol, sehingga senantiasa berhasil.

Jika Anda ingin mengatakan "ukurannya bukan nol", Anda perlu [ -s file.txt ].

Untuk mendapatkan ukuran file, Anda bisa menggunakan wc -cuntuk mendapatkan ukuran (panjang file) dalam byte:

file=file.txt
minimumsize=90000
actualsize=$(wc -c <"$file")
if [ $actualsize -ge $minimumsize ]; then
    echo size is over $minimumsize bytes
else
    echo size is under $minimumsize bytes
fi

Dalam hal ini, sepertinya itulah yang Anda inginkan.

Tapi FYI, jika Anda ingin tahu berapa banyak ruang disk yang digunakan file, Anda bisa menggunakan du -kuntuk mendapatkan ukuran (ruang disk yang digunakan) dalam kilobyte:

file=file.txt
minimumsize=90
actualsize=$(du -k "$file" | cut -f 1)
if [ $actualsize -ge $minimumsize ]; then
    echo size is over $minimumsize kilobytes
else
    echo size is under $minimumsize kilobytes
fi

Jika Anda membutuhkan kontrol lebih besar atas format output, Anda juga dapat melihatnya stat. Di Linux, Anda akan mulai dengan sesuatu seperti stat -c '%s' file.txt, dan pada BSD / Mac OS X, sesuatu seperti stat -f '%z' file.txt.

Mikel
sumber
5
Kenapa du -b "$file" | cut -f 1bukannya stat -c '%s' "$file"? Atau stat --printf="%s" "$file"?
mivk
1
Hanya karena lebih portabel. BSD dan Linux stat memiliki flag yang berbeda.
Mikel
1
Saya harus memodifikasinya ... | cut -d' ' -f1untuk membuatnya bekerja di Ubuntu.
Mikepote
8
Gunakan wc -c < "$file"(perhatikan <), dalam hal ini Anda tidak memerlukan | cut ...bagian (yang, seperti yang diposting, tidak berfungsi pada OSX). Nilai minimum BLOCKSIZEuntuk dupada OSX adalah 512.
mklement0
3
@PetriSirkkala Di sistem Linux saya, wc -c <filenamejuga menggunakan fstatdan seek? Catatan yang fstatmembutuhkan fd, bukan pathname.
Mikel
24

Itu mengejutkan saya bahwa tidak ada yang disebutkan statuntuk memeriksa ukuran file. Beberapa metode pasti lebih baik: menggunakan -suntuk mengetahui apakah file itu kosong atau tidak lebih mudah dari yang lainnya jika itu yang Anda inginkan. Dan jika Anda ingin mencari file dengan ukuran, findtentu cara untuk melakukannya.

Saya juga suka dubanyak mendapatkan ukuran file dalam kb, tetapi, untuk byte, saya akan menggunakan stat:

size=$(stat -f%z $filename) # BSD stat

size=$(stat -c%s $filename) # GNU stat?
Daniel C. Sobral
sumber
2
statadalah ide yang bagus, tetapi pada CentOS inilah yang bekerja untuk saya:size=$(stat -c%s $filename)
Oz Solomon
2
Perbedaan antara GNU dan BSD adalah apa, sayangnya, membuat alternatif ini sedikit kurang menarik. :(
lapo
1
stat bisa menyesatkan jika file jarang. Anda bisa menggunakan blok yang dilaporkan oleh stat untuk menghitung ruang yang digunakan.
Ajith Antony
@AjithAntony Itu poin menarik yang tidak terpikir oleh saya. Saya bisa melihat statmenjadi hal yang benar dalam beberapa situasi, dan file jarang tidak relevan dalam kebanyakan situasi, meskipun tentu saja tidak semua.
Daniel C. Sobral
17

solusi alternatif dengan kurung awk dan double:

FILENAME=file.txt
SIZE=$(du -sb $FILENAME | awk '{ print $1 }')

if ((SIZE<90000)) ; then 
    echo "less"; 
else 
    echo "not less"; 
fi
fstab
sumber
1
Bagus, tetapi tidak akan berfungsi pada OSX, di mana dutidak mendukung -b. (Ini mungkin menjadi pilihan gaya sadar, tetapi hanya untuk menyebutkan alternatif: Anda dapat menghilangkan $dalam awalan (( ... ))ketika referensi variabel: ((SIZE<90000)))
mklement0
1
Sebenarnya itu adalah pengeditan dari pengguna sebelumnya yang berpikir bahwa menghapusnya tidak benar$
fstab
2
@stst, Anda dapat ommit awkdengan menggunakan read( bashperintah internal):read SIZE _ <<<$(du -sb "$FILENAME")
Jdamian
13

Jika Anda findmenangani sintaks ini, Anda dapat menggunakannya:

find -maxdepth 1 -name "file.txt" -size -90k

Ini akan menghasilkan file.txtstdout jika dan hanya jika ukuran file.txtkurang dari 90k. Untuk menjalankan skrip scriptjika file.txtmemiliki ukuran kurang dari 90k:

find -maxdepth 1 -name "file.txt" -size -90k -exec script \;
gniourf_gniourf
sumber
3
+1, tetapi untuk membuatnya berfungsi pada OSX, Anda memerlukan argumen direktori target yang eksplisit, misalnya:find . -maxdepth 1 -name "file.txt" -size -90k
mklement0
8

Jika Anda mencari ukuran file saja:

$ cat $file | wc -c
> 203233
BananaNeil
sumber
1
Ini mungkin jawaban terpendek yang bisa diterapkan, tetapi mungkin juga yang paling lambat. :)
SunSparc
2
Ya, tetapi tentu saja lebih unggul secara ekonomi: Biaya waktu teknik> Biaya waktu perhitungan
BananaNeil
8
wc -c "$file"diberikan sebagai jawaban pada tahun 2011 (tiga tahun lalu). Ya, wc -c "$file"memiliki masalah saat menampilkan nama file serta jumlah karakter, sehingga jawaban awal menambahkan perintah untuk memisahkan jumlah. Tapi wc -c < "$file", yang memperbaiki masalah itu, ditambahkan sebagai komentar pada Mei 2014. Jawaban Anda setara dengan itu, kecuali itu menambahkan "penggunaan yang tidak berguna cat" . Juga, Anda harus mengutip semua referensi variabel shell kecuali Anda memiliki alasan yang bagus untuk tidak melakukannya.
G-Man Mengatakan 'Reinstate Monica'
1
Anda dapat menjadikan ini lebih efisien dengan menggunakan head -c daripada cat.if [$ (head -c 90000 $ file | wc -c) -lt 90000]; lalu gema "File lebih kecil dari 90k"; fi. Diuji pada CentOS, jadi mungkin atau mungkin tidak berfungsi pada BSD atau OSX.
Kevin Keane
@BananaNeil bagaimana melakukan proses ini setiap 20 detik sehingga saya dapat memeriksa peningkatan ukuran file, dan sebagainya?
A Sahra
6

Ini berfungsi baik di linux dan makro

function filesize
{
    local file=$1
    size=`stat -c%s $file 2>/dev/null` # linux
    if [ $? -eq 0 ]
    then
        echo $size
        return 0
    fi

    eval $(stat -s $file) # macos
    if [ $? -eq 0 ]
    then
        echo $st_size
        return 0
    fi

    return -1
}
Neil McGill
sumber
5

stat tampaknya melakukan ini dengan panggilan sistem paling sedikit:

$ 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

sumber
Jika saya memahaminya dengan benar, pengujian harus dilakukan dengan juga pengalihan pipa ?: strace du --bytes $1 2>&1 >/dev/null | wc Jika demikian, maka pada arsitektur amd64 pada ArchLinux (biasanya versi terbaru dari semuanya) Saya memiliki 45 baris untuk du, 46 baris untuk stat, 47 baris untuk wcdan 72 baris untuk find.
VasiliNovikov
5
python -c 'import os; print (os.path.getsize("... filename ..."))'

portabel, semua rasa python, menghindari variasi dalam dialek stat

pengguna6336835
sumber
4

Untuk mendapatkan ukuran file di Linux dan Mac OS X (dan mungkin BSD lainnya), tidak ada banyak pilihan, dan sebagian besar yang disarankan di sini hanya akan bekerja pada satu sistem.

Diberikan f=/path/to/your/file,

apa yang berfungsi di Linux dan Mac Bash:

size=$( perl -e 'print -s shift' "$f" )

atau

size=$( wc -c "$f" | awk '{print $1}' )

Jawaban lain berfungsi dengan baik di Linux, tetapi tidak di Mac:

  • dutidak memiliki -bopsi di Mac, dan trik BLOCKSIZE = 1 tidak berfungsi ("bloksize minimum adalah 512", yang mengarah ke hasil yang salah)

  • cut -d' ' -f1 tidak berfungsi karena di Mac, jumlahnya mungkin lurus, diisi dengan spasi di depan.

Jadi, jika Anda membutuhkan sesuatu yang fleksibel, itu baik perl's -soperator, atau wc -cdisalurkan ke awk '{print $1}'(awk akan mengabaikan spasi terkemuka).

Dan tentu saja, mengenai sisa pertanyaan awal Anda, gunakan -lt(atau -gt) operator:

if [ $size -lt $your_wanted_size ]; then dll.

mivk
sumber
3
+1; jika Anda tahu Anda hanya akan menggunakan ukuran dalam konteks aritmatika (di mana spasi putih terkemuka diabaikan), Anda dapat menyederhanakannya size=$(wc -c < "$f")(perhatikan <, yang menyebabkan wchanya melaporkan angka). Perbandingan ulang: jangan lupa lebih banyak "bash-ful" if (( size < your_wanted_size )); then ...(dan juga [[ $size -lt $your_wanted_size ]]).
mklement0
3

Berdasarkan jawaban gniourf_gniourf,

find "file.txt" -size -90k

akan menulis file.txtke stdout jika dan hanya jika ukuran file.txtkurang dari 90K, dan

temukan "file.txt" -size -90k -exec command \;

akan menjalankan perintah commandjika file.txtmemiliki ukuran kurang dari 90K. Saya sudah menguji ini di Linux. Dari find(1),

... Argumen baris perintah berikut ( dan -H, opsi) dianggap nama file atau direktori yang akan diperiksa, hingga argumen pertama yang dimulai dengan '-', ...-L-P

(penekanan ditambahkan).

G-Man Mengatakan 'Reinstate Monica'
sumber
1
ls -l $file | awk '{print $6}'

dengan asumsi bahwa perintah ls melaporkan file pada kolom # 6

yeugeniuss
sumber
1

Saya akan menggunakan du's --thresholduntuk ini. Tidak yakin apakah opsi ini tersedia di semua versi dutetapi ini diterapkan dalam versi GNU.

Mengutip dari du (1) manual:

-t, --threshold=SIZE
       exclude entries smaller than SIZE if positive, or entries greater
       than SIZE if negative

Inilah solusi saya, gunakan du --threshold=untuk kasus penggunaan OP:

THRESHOLD=90k
if [[ -z "$(du --threshold=${THRESHOLD} file.txt)" ]]; then
    mail -s "file.txt size is below ${THRESHOLD}, please fix. " myemail@gmail.com < /dev/null
    mv -f /root/tmp/file.txt /var/www/file.txt
fi

Keuntungan dari itu, adalah bahwa dudapat menerima argumen untuk opsi itu dalam format yang dikenal - baik manusia seperti dalam 10K, 10MiBatau apa pun yang Anda merasa nyaman dengan - Anda tidak perlu mengkonversi secara manual antara format / unit karena dumenangani itu.

Untuk referensi, inilah penjelasan tentang SIZEargumen ini dari halaman manual:

The SIZE argument is an integer and optional unit (example: 10K is 
10*1024). Units are K,M,G,T,P,E,Z,Y (powers of 1024) or KB,MB,... (powers
of 1000). Binary prefixes can be used, too: KiB=K, MiB=M, and so on.
Doron Behar
sumber
+1 Opsi luar biasa. Sayangnya beberapa dari kita terjebak dengan versi lama duyang tidak mendukungnya. The --thresholdpilihan yang ditambahkan di coreutils 8.21, dirilis pada tahun 2013 .
Amit Naidu
1

Oke, jika Anda menggunakan Mac, lakukan ini: stat -f %z "/Users/Example/config.log" Itu dia!

GarfExiXD
sumber