จะตรวจสอบขนาดของไฟล์โดยใช้ Bash ได้อย่างไร?


145

ฉันมีสคริปต์ที่ตรวจสอบขนาด 0 แต่ฉันคิดว่าต้องมีวิธีที่ง่ายกว่าในการตรวจสอบขนาดไฟล์แทน เช่นfile.txtปกติแล้วคือ 100k; วิธีการตรวจสอบสคริปต์ว่าน้อยกว่า 90k (รวมถึง 0) และทำสำเนาใหม่เพราะไฟล์เสียหายในกรณีนี้

สิ่งที่ฉันกำลังใช้ ..

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

คำตอบ:


250

[ -n file.txt ]ไม่ตรวจสอบขนาดของมันตรวจสอบว่าสตริงfile.txtมีความยาวไม่เป็นศูนย์ดังนั้นจึงจะประสบความสำเร็จเสมอ

ถ้าคุณต้องการที่จะพูดว่า "ขนาดเป็นที่ไม่ใช่ศูนย์" [ -s file.txt ]คุณจะต้อง

ในการรับขนาดไฟล์คุณสามารถใช้wc -cเพื่อรับขนาด (ความยาวไฟล์) เป็นไบต์:

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

ในกรณีนี้ดูเหมือนว่าเป็นสิ่งที่คุณต้องการ

แต่ FYI ถ้าคุณต้องการทราบว่ามีการใช้พื้นที่ดิสก์เท่าใดคุณสามารถใช้du -kเพื่อให้ได้ขนาด (พื้นที่ดิสก์ที่ใช้) ในหน่วยกิโลไบต์:

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

หากคุณต้องการควบคุมรูปแบบผลลัพธ์เพิ่มเติมคุณสามารถดูได้statเช่นกัน บน Linux คุณจะเริ่มต้นด้วยสิ่งที่ชอบstat -c '%s' file.txtและบน BSD / Mac OS X จะเป็นเช่นstat -f '%z' file.txtนั้น


5
ทำไมdu -b "$file" | cut -f 1แทนstat -c '%s' "$file"? หรือstat --printf="%s" "$file"?
mivk

1
เพียงเพราะมันพกพาได้มากกว่า BSD และ Linux stat มีค่าสถานะแตกต่างกัน
มิเคล

1
ฉันต้องแก้ไขมันเพื่อ... | cut -d' ' -f1ให้มันทำงานบน Ubuntu ได้
Mikepote

8
ใช้wc -c < "$file"(โปรดทราบ<) ซึ่งในกรณีนี้คุณไม่จำเป็นต้องใช้ชิ้น| cut ...ส่วน (ซึ่งตามที่โพสต์แล้วไม่สามารถใช้งานได้ใน OSX) ขั้นต่ำBLOCKSIZEค่าสำหรับduใน OSX 512เป็น
mklement0

3
@ PetriSirkkala บนระบบลีนุกซ์ของฉันฉันwc -c <filenameก็ใช้fstatและseek? โปรดทราบว่าfstatใช้ fd ไม่ใช่ชื่อพา ธ
มิเคล

24

มันทำให้ฉันประหลาดใจที่ไม่มีใครพูดถึงstatการตรวจสอบขนาดไฟล์ วิธีการบางอย่างดีกว่าแน่นอน: ใช้-sเพื่อค้นหาว่าไฟล์ว่างเปล่าหรือไม่ง่ายกว่าสิ่งอื่นใดถ้านั่นคือทั้งหมดที่คุณต้องการ และถ้าคุณต้องการค้นหาไฟล์ที่มีขนาดfindย่อมเป็นหนทางที่แน่นอน

ฉันยังชอบduมากที่จะได้ขนาดไฟล์เป็น kb แต่สำหรับไบต์ฉันจะใช้stat:

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

size=$(stat -c%s $filename) # GNU stat?

2
statเป็นความคิดที่ดี แต่ใน CentOS นี่คือสิ่งที่ได้ผลสำหรับฉัน:size=$(stat -c%s $filename)
23490 Oz โซโลมอน

2
ความแตกต่างระหว่าง GNU และ BSD เป็นสิ่งที่น่าเสียดายที่ทำให้ทางเลือกนี้น่าสนใจน้อยลง :(
lapo

1
สถิติสามารถทำให้เข้าใจผิดหากไฟล์กระจัดกระจาย คุณสามารถใช้บล็อคที่รายงานโดยสถิติเพื่อคำนวณพื้นที่ที่ใช้
Ajith Antony

@AjithAntony นั่นเป็นจุดที่น่าสนใจที่ไม่ได้เกิดขึ้นกับฉัน ฉันเห็นstatว่าสิ่งที่ถูกต้องในบางสถานการณ์และไฟล์ที่กระจัดกระจายไม่เกี่ยวข้องในสถานการณ์ส่วนใหญ่แม้ว่าจะไม่ใช่ทั้งหมด
Daniel C. Sobral

17

โซลูชันทางเลือกที่มี awk และวงเล็บคู่:

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

if ((SIZE<90000)) ; then 
    echo "less"; 
else 
    echo "not less"; 
fi

1
ดี แต่ไม่ทำงานบน OSX ซึ่งduไม่รองรับ-bไม่สนับสนุน(อาจจะเป็นทางเลือกสไตล์ที่ใส่ใจ แต่เพียงแค่พูดถึงทางเลือก: คุณสามารถละเว้น$ภายในคำนำหน้า(( ... ))เมื่ออ้างอิงตัวแปร((SIZE<90000)))
mklement0

1
ที่จริงแล้วมันเป็นการแก้ไขจากผู้ใช้ก่อนหน้านี้ซึ่งคิดว่าผิดที่จะละเว้น$
fstab

2
@fstab คุณสามารถ ommit awkโดยใช้read( bashคำสั่งภายใน):read SIZE _ <<<$(du -sb "$FILENAME")
Jdamian

13

หากคุณfindจัดการกับไวยากรณ์นี้คุณสามารถใช้:

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

สิ่งนี้จะส่งออกfile.txtไปยัง stdout ถ้าหากขนาดfile.txtน้อยกว่า 90k หากต้องการรันสคริปต์scriptหากfile.txtมีขนาดน้อยกว่า 90k:

find -maxdepth 1 -name "file.txt" -size -90k -exec script \;

3
+1 แต่เพื่อให้ทำงานบน OSX ได้คุณต้องมีอาร์กิวเมนต์ไดเรกทอรีเป้าหมายที่ชัดเจนเช่น:find . -maxdepth 1 -name "file.txt" -size -90k
mklement0

8

หากคุณกำลังมองหาขนาดของไฟล์:

$ cat $file | wc -c
> 203233

1
นี่อาจเป็นคำตอบที่สั้นที่สุดที่สามารถใช้งานได้ แต่อาจเป็นคำตอบที่ช้าที่สุดด้วย :)
SunSparc

2
ใช่ แต่เหนือกว่าอย่างแน่นอนในเชิงเศรษฐศาสตร์: ต้นทุนของเวลาวิศวกรรม> ต้นทุนในการคำนวณเวลา
BananaNeil

8
wc -c "$file"ได้รับเป็นคำตอบในปี 2011 (สามปีที่ผ่านมา) ใช่wc -c "$file"มีปัญหาว่าจะส่งออกชื่อไฟล์เช่นเดียวกับจำนวนตัวอักษรดังนั้นคำตอบก่อนหน้านี้ได้เพิ่มคำสั่งเพื่อแยกการนับ แต่wc -c < "$file"ซึ่งการแก้ไขปัญหาที่ถูกเพิ่มเข้ามาเป็นความคิดเห็นพฤษภาคม 2014 คำตอบของคุณคือเท่ากับว่านอกจากจะเพิ่ม“การใช้ไร้ประโยชน์cat นอกจากนี้คุณควรอ้างอิงการอ้างอิงตัวแปรเชลล์ทั้งหมดยกเว้นว่าคุณมีเหตุผลที่ดีที่จะไม่อ้างอิง
G-Man กล่าวว่า 'Reinstate Monica'

1
คุณสามารถทำให้มีประสิทธิภาพมากขึ้นโดยใช้ head -c แทน cat.if [$ (head -c 90000 $ file | wc -c) -lt 90000]; echo "ไฟล์มีขนาดเล็กกว่า 90k"; fi. ทดสอบบน CentOS ดังนั้นอาจทำงานได้กับ BSD หรือ OSX
Kevin Keane

@BananaNeil จะทำกระบวนการนี้อย่างไรในแต่ละ 20 วินาทีเพื่อให้ฉันสามารถตรวจสอบการเพิ่มขนาดของไฟล์ได้หรือไม่
Sahra

6

ใช้งานได้ทั้ง linux และ macos

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
}

5

สถิติดูเหมือนว่าจะทำสิ่งนี้ด้วยการเรียกระบบน้อยที่สุด:

$ 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

ถ้าฉันเข้าใจถูกต้องควรทำการทดสอบด้วยการเปลี่ยนเส้นทางไปป์ด้วยหรือไม่: strace du --bytes $1 2>&1 >/dev/null | wc ถ้าเป็นอย่างนั้นสถาปัตยกรรม amd64 บน ArchLinux (โดยทั่วไปคือทุกอย่างล่าสุด) ฉันมี 45 บรรทัดสำหรับdu46 บรรทัดสำหรับstat47 บรรทัดสำหรับwcและ 72 findเส้น
VasiliNovikov

5
python -c 'import os; print (os.path.getsize("... filename ..."))'

พกพาทุกรสชาติของงูหลามหลีกเลี่ยงการเปลี่ยนแปลงในภาษาถิ่น


4

สำหรับการรับขนาดไฟล์ทั้งใน Linux และ Mac OS X (และ BSD อื่น ๆ น่าจะเป็นไปได้) มีตัวเลือกไม่มากและส่วนใหญ่ที่แนะนำในที่นี้จะใช้ได้กับระบบเดียวเท่านั้น

ป.ร. ให้ไว้ f=/path/to/your/fileไว้

ทำงานได้ทั้งใน Linux และ Mac 's Bash:

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

หรือ

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

คำตอบอื่น ๆ ทำงานได้ดีใน Linux แต่ไม่ใช่ใน Mac:

  • duไม่มี-bตัวเลือกใน Mac และเคล็ดลับ BLOCKSIZE = 1 ไม่ทำงาน ("การบล็อกขั้นต่ำคือ 512" ซึ่งนำไปสู่ผลลัพธ์ที่ไม่ถูกต้อง)

  • cut -d' ' -f1 ไม่ทำงานเนื่องจากบน Mac ตัวเลขอาจจัดตำแหน่งชิดขวามีช่องว่างด้านหน้า

ดังนั้นหากคุณต้องการบางสิ่งบางอย่างที่ยืดหยุ่นก็อาจperlเป็น-sผู้ดำเนินwc -cการawk '{print $1}' (awk จะไม่สนใจพื้นที่สีขาวนำ)

และแน่นอนเกี่ยวกับคำถามที่เหลือของคุณให้ใช้โอเปอเรเตอร์-lt(หรือ-gt):

if [ $size -lt $your_wanted_size ]; then เป็นต้น


3
+1; หากคุณรู้ว่าคุณจะใช้ขนาดในบริบททางคณิตศาสตร์เท่านั้น (โดยที่ละเว้นช่องว่างนำหน้า) คุณสามารถทำให้ง่ายขึ้นsize=$(wc -c < "$f")(สังเกตสิ่ง<ที่ทำให้wcรายงานตัวเลขเท่านั้น) การเปรียบเทียบ Re: อย่าลืม "bash-ful" มากกว่าif (( size < your_wanted_size )); then ...(และ[[ $size -lt $your_wanted_size ]])
mklement0

3

ขึ้นอยู่กับคำตอบของ gniourf_gniourf

find "file.txt" -size -90k

จะเขียนfile.txtถึง stdout หากว่ามีขนาดfile.txtน้อยกว่า 90K และ

ค้นหา "file.txt" -size -90k -exec คำสั่ง \;

จะดำเนินการคำสั่งcommandหากfile.txtมีขนาดน้อยกว่า 90K ฉันได้ทดสอบสิ่งนี้บน Linux แล้ว จากfind(1),

…อาร์กิวเมนต์บรรทัดคำสั่งต่อไปนี้ ( -H , -Lและ-Pตัวเลือก) จะถูกนำไปเป็นชื่อของไฟล์หรือไดเรกทอรีที่จะตรวจสอบถึงอาร์กิวเมนต์แรกที่เริ่มต้นด้วย '-' ...

(เน้นที่เพิ่ม)



1

ผมจะใช้du's --thresholdสำหรับการนี้ ไม่แน่ใจว่าตัวเลือกนี้มีให้บริการในทุกรุ่นหรือไม่duแต่จะใช้งานในรุ่นของ GNU

การอ้างอิงจากคู่มือของdu (1) :

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

นี่คือทางออกของฉันใช้du --threshold=สำหรับกรณีการใช้ 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

ประโยชน์ของการที่เป็นที่duสามารถยอมรับข้อโต้แย้งไปที่ตัวเลือกที่อยู่ในรูปแบบที่เป็นที่รู้จัก - คนไม่ว่าจะเป็นใน10K, 10MiBหรือสิ่งที่คุณเคยรู้สึกสะดวกสบายกับ - คุณไม่จำเป็นต้องแปลงด้วยตนเองระหว่างรูปแบบ / หน่วยตั้งแต่duจับได้ว่า

สำหรับการอ้างอิงต่อไปนี้เป็นคำอธิบายเกี่ยวกับSIZEอาร์กิวเมนต์นี้จากหน้า man:

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.

+1 ตัวเลือกที่ยอดเยี่ยม น่าเสียดายที่เราบางคนติดอยู่กับรุ่นเก่ากว่าduที่ไม่สนับสนุน --thresholdตัวเลือกที่ถูกเพิ่มเข้ามาใน coreutils 8.21, การปล่อยตัวในปี 2013
Amit Naidu

1

ตกลงถ้าคุณใช้ Mac ให้ทำสิ่งนี้: แค่ stat -f %z "/Users/Example/config.log" นั้นแหละ!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.