Bash scripting: ทดสอบไดเรกทอรีว่าง


95

ฉันต้องการทดสอบว่าไดเรกทอรีไม่มีไฟล์ใด ๆ หรือไม่ ถ้าเป็นเช่นนั้นฉันจะข้ามการประมวลผล

ฉันพยายามต่อไปนี้:

if [ ./* == "./*" ]; then
    echo "No new file"
    exit 1
fi

ที่ให้ข้อผิดพลาดต่อไปนี้:

line 1: [: too many arguments

มีวิธีแก้ปัญหา / ทางเลือกหรือไม่?


เกี่ยวข้อง: stackoverflow.com/q/91368/52074
Trevor Boyd Smith

คำตอบ:


121
if [ -z "$(ls -A /path/to/dir)" ]; then
   echo "Empty"
else
   echo "Not Empty"
fi

นอกจากนี้ยังเป็นการดีหากตรวจสอบว่ามีไดเรกทอรีอยู่ก่อนหรือไม่


11
อย่าใช้&&และ||พร้อมกัน! หากecho "Not Empty"ล้มเหลวecho "Empty"จะทำงาน! ลองecho "test" && false || echo "fail"! ใช่ฉันรู้ว่าechoจะไม่ล้มเหลว แต่ถ้าคุณเปลี่ยนคำสั่งอื่น ๆ คุณจะแปลกใจ!
uzsolt

4
โปรดระบุตัวอย่างอย่างน้อยหนึ่งรหัสเมื่อโค้ดด้านบนใช้งานไม่ได้ รหัสนี้ถูกต้องอย่างแน่นอน ฉันหวังว่าผู้ถามสามารถปรับตัวนี้เพื่อจุดประสงค์ของเขาเอง
Andrey Atapin

3
[ "$(ls -A /)" ] && touch /non-empty || echo "Empty"- ถ้าคุณต้องการ "ทำเครื่องหมาย" dirs ที่ไม่ว่างพร้อมชื่อไฟล์ที่สร้างขึ้นnon-emptyจะล้มเหลวและพิมพ์ "Empty"
uzsolt

4
อยู่ที่ไหนtouch /emptyในสายของฉัน
Andrey Atapin

7
ไม่นะ! มีปัญหาสำคัญกับรหัสนี้ มันควรจะเป็นif [ -n "$(ls -A /path/to/dir)" ]; then... โปรดอัปเดตคำตอบก่อนที่จะมีคนวางรหัสนี้ลงในเซิร์ฟเวอร์ของพวกเขาที่ใดที่หนึ่งและแฮ็กเกอร์จะหาวิธีใช้ประโยชน์จากมัน หาก/path/to/dirไม่ว่างเปล่าชื่อไฟล์นั้นจะถูกส่งผ่านเป็นอาร์กิวเมนต์/bin/testซึ่งไม่ชัดเจน เพียงเพิ่ม-nอาร์กิวเมนต์แก้ปัญหา ขอบคุณ!
Edward Ned Harvey

21

ไม่จำเป็นต้องนับสิ่งใด ๆ หรือเปลือก globs นอกจากนี้คุณยังสามารถใช้ร่วมกับread findหากfindเอาต์พุตของว่างเปล่าคุณจะกลับมาfalse:

if find /some/dir -mindepth 1 | read; then
   echo "dir not empty"
else
   echo "dir empty"
fi

ควรเป็นแบบพกพา


วิธีแก้ปัญหาที่ดี แต่ฉันคิดว่าการechoโทรของคุณสะท้อนผลลัพธ์ที่ไม่ถูกต้อง: ในการทดสอบของฉัน (ภายใต้ Cygwin) find . -mindepth 1 | readมีรหัสข้อผิดพลาด 141 รหัสในรหัสที่ไม่ว่างเปล่าและ 0 ในรหัสที่ว่างเปล่า
Lucas Cimon

@LucasCimon ไม่ได้อยู่ที่นี่ (macOS และ GNU / Linux) สำหรับไดเร็กทอรีที่ไม่มีค่าว่างให้readส่งคืน 0 และสำหรับไดเร็กทอรีว่าง 1
slhck

1
PSA ไม่ทำงานกับset -o pipefail
พันเอกสามสิบสอง

19
if [ -n "$(find "$DIR_TO_CHECK" -maxdepth 0 -type d -empty 2>/dev/null)" ]; then
    echo "Empty directory"
else
    echo "Not empty or NOT a directory"
fi

ถูกต้องและรวดเร็ว ดี!
l0b0

4
จำเป็นต้องมีเครื่องหมายคำพูด (2x) และการทดสอบ-nจะถูกต้องและปลอดภัย (ทดสอบกับไดเรกทอรีที่มีช่องว่างในชื่อทดสอบด้วยไดเรกทอรีที่ไม่ว่างเปล่าที่มีชื่อ '0 = 1') ... [ -n "$(find "$DIR_TO_CHECK" -maxdepth 0 -type d -empty 2>/dev/null)" ]; ...
Zrin

1
@ivan_pozdeev นั่นไม่จริงอย่างน้อยสำหรับ GNU พบ grepคุณอาจจะคิดของ serverfault.com/questions/225798/…
Vladimir Panteleev

มันอาจจะง่ายกว่าในการเขียนfind "$DIR_TO_CHECK" -maxdepth 0 -type d -empty | grep .และพึ่งพาสถานะทางออกจาก grep ไม่ว่าคุณจะทำแบบไหนนี่เป็นคำตอบที่ถูกต้องสำหรับคำถามนี้
Tom Anderson

13
#!/bin/bash
if [ -d /path/to/dir ]; then
    # the directory exists
    [ "$(ls -A /path/to/dir)" ] && echo "Not Empty" || echo "Empty"
else
    # You could check here if /path/to/dir is a file with [ -f /path/to/dir]
fi

4
จะต้องเป็นมันไม่จำเป็นต้องแยกวิเคราะห์ ls เอาท์พุทเพียงแค่ดูว่ามันว่างเปล่าหรือไม่ ใช้การค้นหาเพียงแค่รู้สึกว่าเกินความเป็นตัวฉัน
akostadinov

4

สิ่งนี้จะทำงานในไดเรกทอรีการทำงานปัจจุบัน (.):

[ `ls -1A . | wc -l` -eq 0 ] && echo "Current dir is empty." || echo "Current dir has files (or hidden files) in it."

หรือคำสั่งเดียวกันแบ่งออกเป็นสามบรรทัดเพื่อให้อ่านง่ายขึ้น:

[ `ls -1A . | wc -l` -eq 0 ] && \
echo "Current dir is empty." || \
echo "Current dir has files (or hidden files) in it."

เพียงแทนที่ ls -1A . | wc -lด้วยls -1A <target-directory> | wc -lถ้าคุณต้องการเรียกใช้บนโฟลเดอร์เป้าหมายอื่น

แก้ไข : ฉันแทนที่-1aด้วย-1A(ดูความคิดเห็น @Daniel)


2
ใช้ls -Aแทน ระบบไฟล์บางระบบไม่มี.และ..ลิงก์สัญลักษณ์ตามเอกสาร
Daniel Beck

1
ขอบคุณ @Daniel ฉันแก้ไขคำตอบของคุณหลังจากที่คุณแนะนำ ฉันรู้ว่า "1" อาจถูกลบเช่นกัน
ztank1013

2
มันไม่เจ็บ แต่มันส่อให้เห็นถ้ามันไม่ได้ส่งออกไปยังสถานี เนื่องจากคุณส่งไปยังโปรแกรมอื่นมันซ้ำซ้อน
Daniel Beck

-1ซ้ำซ้อนแน่นอน แม้ว่าlsจะไม่ได้พิมพ์หนึ่งรายการต่อบรรทัดเมื่อมันจะถูกไพพ์แล้วมันจะไม่ส่งผลกระทบต่อแนวคิดในการตรวจสอบว่ามันจะสร้างศูนย์หรือมากกว่านั้น
Victor Yarema

3

ใช้สิ่งต่อไปนี้:

count="$( find /path -mindepth 1 -maxdepth 1 | wc -l )"
if [ $count -eq 0 ] ; then
   echo "No new file"
   exit 1
fi

lsวิธีนี้คุณจะเป็นอิสระจากรูปแบบการส่งออกของ -mindepthข้ามไดเรกทอรีเอง-maxdepthป้องกันการเรียกซ้ำไปยังไดเรกทอรีย่อยซ้ำ ๆ เพื่อเร่งความเร็ว


แน่นอนคุณตอนนี้ขึ้นอยู่กับการwc -lและfindรูปแบบการออก (ซึ่งเป็นธรรมดาพอสมควรแม้ว่า)
Daniel Beck

3

ใช้อาร์เรย์:

files=( * .* )
if (( ${#files[@]} == 2 )); then
    # contents of files array is (. ..)
    echo dir is empty
fi

3
เป็นวิธีที่ดีมาก แต่โปรดทราบว่ามันจำเป็นต้องใช้shopt -s nullglob
xebeche

3
${#files[@]} == 2สมมติฐานไม่ได้ยืนสำหรับ dir ราก (คุณอาจจะไม่ทดสอบว่ามันว่างเปล่า แต่รหัสบางอย่างที่ไม่ทราบเกี่ยวกับข้อ จำกัด ที่อาจ)
ivan_pozdeev

3

วิธีแฮ็ก แต่ใช้วิธีทุบตีเท่านั้นไม่มี PID:

is_empty() {
    test -e "$1/"* 2>/dev/null
    case $? in
        1)   return 0 ;;
        *)   return 1 ;;
    esac
}

สิ่งนี้ใช้ประโยชน์จากความจริงที่ว่าtestbuiltin ออกด้วย 2 หากได้รับมากกว่าหนึ่งอาร์กิวเมนต์หลังจาก-e: ก่อนอื่น"$1"/*glob จะถูกขยายโดยการทุบตี ผลลัพธ์นี้มีหนึ่งอาร์กิวเมนต์ต่อไฟล์ ดังนั้น

  • หากไม่มีไฟล์เครื่องหมายดอกจันtest -e "$1"*จะไม่ขยายดังนั้นเชลล์จะกลับไปใช้ชื่อไฟล์*ซึ่งจะส่งคืน 1

  • ... ยกเว้นถ้ามีไฟล์เดียวชื่อจริง ๆ*แล้วเครื่องหมายดอกจันจะขยายออกไปเป็นอย่างดีเครื่องหมายดอกจันซึ่งจบลงด้วยการโทรเช่นเดียวกับข้างต้นคือ test -e "dir/*"เพียงแค่คราวนี้กลับมาเป็น 0 (ขอบคุณ @TrueY ที่ชี้ให้เห็น)

  • หากมีไฟล์เดียวให้test -e "dir/file"รันซึ่งจะส่งคืน 0

  • แต่ถ้ามีไฟล์มากกว่า 1 ไฟล์test -e "dir/file1" "dir/file2" จะถูกรันซึ่ง bash จะรายงานว่าเป็นข้อผิดพลาดในการใช้งานเช่น 2

case ล้อมรอบตรรกะทั้งหมดเพื่อให้เฉพาะกรณีแรกที่มีสถานะการออก 1 สถานะถูกรายงานว่าประสบความสำเร็จ

ปัญหาที่เป็นไปได้ที่ฉันยังไม่ได้ตรวจสอบ:

  • มีไฟล์มากกว่าจำนวนอาร์กิวเมนต์ที่อนุญาต - ฉันเดาว่านี่อาจทำงานคล้ายกับกรณีที่มี 2+ ไฟล์

  • หรือมีชื่อไฟล์ว่างเปล่าจริง ๆ - ฉันไม่แน่ใจว่าเป็นไปได้ในระบบปฏิบัติการ / FS ใด ๆ


1
การแก้ไขเล็กน้อย: หากไม่มีไฟล์ใน dir / test -e dir/*จะมีการเรียกใช้ หากไฟล์เดียวคือ '*' ใน dir การทดสอบจะคืนค่า 0 หากมีไฟล์มากกว่านั้นก็จะส่งคืน 2 ดังนั้นจึงทำงานตามที่อธิบายไว้
TrueY

คุณพูดถูกแล้ว @TrueY ฉันรวมไว้ในคำตอบแล้ว ขอบคุณ!
Alois Mahdal

2

ด้วย FIND (1) (ภายใต้ Linux และ FreeBSD) คุณสามารถดูรายการไดเรกทอรีซ้ำผ่าน "-maxdepth 0" และทดสอบว่าว่างด้วย "-empty" หรือไม่ นำไปใช้กับคำถามที่ให้:

if test -n "$(find ./ -maxdepth 0 -empty)" ; then
    echo "No new file"
    exit 1
fi

มันอาจจะไม่พกพาได้ 100% แต่มันก็สง่างาม
Craig Ringer

1

ฉันคิดว่าทางออกที่ดีที่สุดคือ:

files=$(shopt -s nullglob; shopt -s dotglob; echo /MYPATH/*)
[[ "$files" ]] || echo "dir empty" 

ขอบคุณhttps://stackoverflow.com/a/91558/520567

นี่คือการแก้ไขคำตอบของฉันแบบไม่ระบุชื่อที่อาจมีหรือไม่มีประโยชน์กับใครสักคน: การแก้ไขเล็กน้อยจะทำให้จำนวนไฟล์:

files=$(shopt -s nullglob dotglob; s=(MYPATH/*); echo ${s[*]}) 
echo "MYPATH contains $files files"

สิ่งนี้จะทำงานได้อย่างถูกต้องแม้ว่าชื่อไฟล์จะมีช่องว่าง


1
if find "${DIR}" -prune ! -empty -exit 1; then
    echo Empty
else
    echo Not Empty
fi

แก้ไข: ฉันคิดว่าการแก้ปัญหานี้ทำงานได้ดีกับ GNU หาหลังจากได้อย่างรวดเร็วดูที่การดำเนินงาน แต่ตอนนี้อาจไม่ทำงานกับตัวอย่างเช่นNetBSD หา อันที่จริงนั้นใช้ฟิลด์ st_size ของ stat (2) คู่มืออธิบายเป็น:

st_size            The size of the file in bytes.  The meaning of the size
                   reported for a directory is file system dependent.
                   Some file systems (e.g. FFS) return the total size used
                   for the directory metadata, possibly including free
                   slots; others (notably ZFS) return the number of
                   entries in the directory.  Some may also return other
                   things or always report zero.

ทางออกที่ดีกว่าง่ายกว่าคือ:

if find "${DIR}" -mindepth 1 -exit 1; then
    echo Empty
else
    echo Not Empty
fi

นอกจากนี้ -prune ในโซลูชันที่ 1 ก็ไม่มีประโยชน์เช่นกัน

แก้ไข: ไม่ออกสำหรับ gnu find .. ทางออกข้างต้นนั้นดีสำหรับการค้นหาของ NetBSD สำหรับ GNU พบสิ่งนี้ควรใช้:

if [ -z "`find \"${DIR}\" -mindepth 1 -exec echo notempty \; -quit`" ]; then
    echo Empty
else
    echo Not Empty
fi

ค้นหาจากfindutils GNU 4.6.0 (รุ่นล่าสุด) ไม่ได้รับการ-exitวินิจฉัย
เดนนิส

0

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

#!/bin/bash
if [ "$#" == "0" ]; then 
find . -maxdepth 1 -type d -exec findempty "{}"  \;
exit
fi

COUNT=`ls -1A "$*" | wc -l`
if [ "$COUNT" == "0" ]; then 
echo "$* : $COUNT"
fi

0

การทำงานนี้สำหรับฉันเพื่อตรวจสอบและประมวลผลไฟล์ในไดเรกทอรีการ../INพิจารณาสคริปต์อยู่ใน../Scriptไดเรกทอรี:

FileTotalCount=0

    for file in ../IN/*; do
    FileTotalCount=`expr $FileTotalCount + 1`
done

if test "$file" = "../IN/*"
then

    echo "EXITING: NO files available for processing in ../IN directory. "
    exit

else

  echo "Starting Process: Found ""$FileTotalCount"" files in ../IN directory for processing."

# Rest of the Code

0

สิ่งที่เกี่ยวกับการทดสอบถ้าไดเรกทอรีมีอยู่และไม่ว่างในหนึ่งถ้าคำสั่ง

if [[ -d path/to/dir && -n "$(ls -A path/to/dir)" ]]; then 
  echo "directory exists"
else
  echo "directory doesn't exist"
fi

-1

ไดเรกทอรีอื่น ๆ กว่าหนึ่งในปัจจุบันใด ๆ คุณสามารถตรวจสอบว่าเป็นที่ว่างเปล่าโดยพยายามที่จะrmdirมันเพราะrmdirมีการประกันที่จะล้มเหลวสำหรับไดเรกทอรีที่ไม่ว่างเปล่า หากrmdirประสบความสำเร็จและคุณต้องการให้ไดเรกทอรีว่างเพื่อเอาตัวรอดจากการทดสอบให้ลองmkdirอีกครั้ง

อย่าใช้แฮ็คนี้หากมีกระบวนการอื่น ๆ ที่อาจถูกยกเลิกการรวบรวมโดยไดเรกทอรีที่พวกเขารู้เกี่ยวกับการหยุดอยู่ชั่วครู่

หากrmdirไม่ได้ผลสำหรับคุณและคุณอาจกำลังทดสอบไดเรกทอรีที่อาจมีไฟล์จำนวนมากวิธีแก้ปัญหาใด ๆ ที่ใช้การทำงานแบบกลม globbing อาจทำให้ช้าลงและ / หรือทำงานในขีดจำกัดความยาวบรรทัดคำสั่ง น่าจะดีกว่าที่จะใช้findในกรณีนี้ findทางออกที่เร็วที่สุดที่ฉันนึกได้

is_empty() {
    test -z $(find "$1" -mindepth 1 -printf X -quit)
}

สิ่งนี้ใช้ได้กับ GNU และ BSD เวอร์ชันfindแต่ไม่ใช่สำหรับ Solaris one ซึ่งหายไปทุก ๆ อันของfindโอเปอเรเตอร์เหล่านั้น รักงานของคุณออราเคิล


ไม่ใช่ความคิดที่ดี OP ต้องการทดสอบว่าไดเรกทอรีว่างเปล่าหรือไม่
roaima

-3

คุณสามารถลองลบไดเรกทอรีและรอข้อผิดพลาด; rmdirจะไม่ลบไดเรกทอรีหากไม่ว่างเปล่า

_path="some/path"
if rmdir $_path >/dev/null 2>&1; then
   mkdir $_path        # create it again
   echo "Empty"
else
   echo "Not empty or doesn't exist"
fi

3
-1 นี่คือประเภทของรหัสที่ย้อนกลับ rmdirจะล้มเหลวถ้าฉันไม่มีสิทธิ์ลบไดเรกทอรี; หรือถ้าเป็น Bvfs subvolume หรือถ้าเป็นของระบบไฟล์แบบอ่านอย่างเดียว และถ้าrmdirไม่ล้มเหลวและmkdirทำงาน: จะทำอย่างไรถ้าไดเรกทอรีที่ถูกลบไปแล้วนั้นเป็นของผู้ใช้รายอื่น? สิ่งที่เกี่ยวกับการอนุญาต (อาจจะไม่ได้มาตรฐาน)? ACL? คุณสมบัติเพิ่มเติม? ที่หายไปทั้งหมด
Kamil Maciorowski

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