ตรวจสอบจากเชลล์สคริปต์ว่าไดเร็กทอรีมีไฟล์หรือไม่


117

จากเชลล์สคริปต์ฉันจะตรวจสอบได้อย่างไรว่าไดเร็กทอรีมีไฟล์หรือไม่

สิ่งที่คล้ายกับสิ่งนี้

if [ -e /some/dir/* ]; then echo "huzzah"; fi;

แต่จะใช้งานได้ถ้าไดเร็กทอรีมีไฟล์เดียวหรือหลายไฟล์ (ไฟล์ด้านบนใช้ได้กับไฟล์ 0 หรือ 1 ไฟล์เท่านั้น)


สิ่งที่ควรค่าแก่ตัวอย่างของคุณทำในสิ่งที่คุณต้องการใน ksh และ zsh
Dave Webb

2
@DaveWebb ไม่มันไม่ได้ หากลูกโลกขยายเป็นมากกว่าหนึ่งคำการทดสอบ zsh จะรายงาน 'การทดสอบ: อาร์กิวเมนต์มากเกินไป'
Jens

"huzzah" หมายถึง "ไดเรกทอรีไม่ว่างเปล่า"
funroll

หากไดเร็กทอรีมีไดเร็กทอรีย่อยว่างเท่านั้นจะนับว่า "มีไฟล์" หรือไม่
Keith Thompson

ที่เกี่ยวข้อง: การค้นหาไดเรกทอรีว่าง UNIX
Joseph Holsten

คำตอบ:


72

โซลูชันที่ใช้จนถึงปัจจุบัน lsปัจจุบัน นี่คือวิธีแก้ปัญหาทุบตีทั้งหมด:

#!/bin/bash
shopt -s nullglob dotglob     # To include hidden files
files=(/some/dir/*)
if [ ${#files[@]} -gt 0 ]; then echo "huzzah"; fi

8
ตราบเท่าที่คุณจำไว้ว่าให้ตั้งค่าตัวเลือกกลับไปเป็นค่าเดิมในตอนท้ายของสคริปต์ :)
Jean

นี่เป็นเวอร์ชันที่ปรับปรุงเล็กน้อยซึ่งดูแลการรีเซ็ตการตั้งค่า bash:shopt -q nullglob || resetnullglob=1; shopt -s nullglob; shopt -q dotglob || resetdotglob=1; shopt -s dotglob; files=(/some/dir/*); [ "$files" ] && echo "wowzers"; [ "$resetdotglob" ] && shopt -u dotglob; [ "$resetnullglob" ] && shopt -u nullglob;
user123444555621

12
ทำไมไม่ใช้ subshell เพื่อรีเซ็ตการตั้งค่า:files=$(shopt -s nullglob;shopt -s dotglob;echo /some/dir/*)
teambob

7
@teambob หากใช้ sub-shell: files=$(shopt -s nullglob;shopt -s dotglob;echo /some/dir/*) คำสั่ง if ควรเปลี่ยนเป็นif [ ${#files} -gt 0 ];หรือบางทีคุณอาจลืม () รอบคำสั่ง sub-shell? files=($(shopt -s nullglob;shopt -s dotglob;echo /some/dir/*))
stoutyhk

2
@stoutyhk $ (... ) เรียกคืนการตั้งค่าโดยไม่จำเป็นต้องใช้ subshell แยกต่างหาก การใช้ $ (... ) สร้างอินสแตนซ์ใหม่ของเชลล์ สภาพแวดล้อมของอินสแตนซ์ใหม่นี้จะถูกยกเลิกเมื่อคำสั่งเสร็จสิ้น แก้ไข: พบข้อมูลอ้างอิง tldp.org/LDP/abs/html/commandsub.html "การแทนที่คำสั่งเรียกใช้ subshell"
teambob

140

สามเทคนิคที่ดีที่สุด


shopt -s nullglob dotglob; f=your/dir/*; ((${#f}))

เคล็ดลับนี้ 100% bashและเรียกใช้ (spawns) เปลือกย่อย แนวคิดนี้มาจากBruno De Fraineและปรับปรุงโดยความคิดเห็นของteambob

files=$(shopt -s nullglob dotglob; echo your/dir/*)
if (( ${#files} ))
then
  echo "contains files"
else 
  echo "empty (or does not exist or is a file)"
fi

บันทึก:ไม่มีความแตกต่างระหว่างไดเร็กทอรีว่างกับไดเร็กทอรีที่ไม่มีอยู่ (และแม้ว่าพา ธ ที่ให้มาจะเป็นไฟล์ก็ตาม)

มีทางเลือกอื่นที่คล้ายกันและรายละเอียดเพิ่มเติม (และตัวอย่างเพิ่มเติม) ในคำถามที่พบบ่อย'อย่างเป็นทางการ'สำหรับช่อง #bash IRC :

if (shopt -s nullglob dotglob; f=(*); ((${#f[@]})))
then
  echo "contains files"
else 
  echo "empty (or does not exist, or is a file)"
fi

[ -n "$(ls -A your/dir)" ]

เคล็ดลับนี้เป็นแรงบันดาลใจจากบทความ nixCraft ของโพสต์ในปี 2007 เพิ่มการปราบปรามการผิดพลาดในการส่งออก2>/dev/null ดูคำตอบของAndrew Taylor (2008) และคำตอบของgr8can8dian (2011) ด้วย"No such file or directory"

if [ -n "$(ls -A your/dir 2>/dev/null)" ]
then
  echo "contains files (or is a file)"
else
  echo "empty (or does not exist)"
fi

หรือเวอร์ชัน bashism บรรทัดเดียว:

[[ $(ls -A your/dir) ]] && echo "contains files" || echo "empty"

หมายเหตุ: lsส่งคืน$?=2เมื่อไม่มีไดเร็กทอรี แต่ไม่มีความแตกต่างระหว่างไฟล์และไดเร็กทอรีว่าง


[ -n "$(find your/dir -prune -empty)" ]

เคล็ดลับสุดท้ายนี้ได้รับแรงบันดาลใจจากคำตอบของ Gravstarซึ่ง-maxdepth 0ถูกแทนที่ด้วย-pruneและปรับปรุงโดยความคิดเห็นของphils

if [ -n "$(find your/dir -prune -empty 2>/dev/null)" ]
then
  echo "empty (directory or file)"
else
  echo "contains files (or does not exist)"
fi

รูปแบบโดยใช้-type d:

if [ -n "$(find your/dir -prune -empty -type d 2>/dev/null)" ]
then
  echo "empty directory"
else
  echo "contains files (or does not exist or is not a directory)"
fi

คำอธิบาย:

  • find -prune คล้ายกว่า find -maxdepth 0ใช้อักขระน้อย
  • find -empty พิมพ์ไดเร็กทอรีว่างและไฟล์
  • find -type d พิมพ์ไดเร็กทอรีเท่านั้น

หมายเหตุ:คุณสามารถแทนที่ได้[ -n "$(find your/dir -prune -empty)" ]โดยใช้เวอร์ชันย่อด้านล่าง:

if [ `find your/dir -prune -empty 2>/dev/null` ]
then
  echo "empty (directory or file)"
else
  echo "contains files (or does not exist)"
fi

รหัสสุดท้ายนี้ใช้งานได้เกือบทุกกรณี แต่โปรดทราบว่าเส้นทางที่เป็นอันตรายอาจแสดงคำสั่ง ...


2
ฉันคิดว่าคุณสามารถลดความซับซ้อนของตัวเลือกการค้นหา[ -n "$(find "your/dir" -prune -empty)" ]เพื่อหลีกเลี่ยงการซ้ำซ้อนของเส้นทางไดเร็กทอรี
Phils

ในขณะที่ใช้if [ ``ls -A your/dir`` ]ในสคริปต์ฉันได้ข้อสรุปว่ามันทำงานได้ดีสำหรับไดเร็กทอรีที่มีไดเร็กทอรีย่อย 0, 1 หรือ 2 แต่ล้มเหลวสำหรับไดเร็กทอรีที่มีไดเร็กทอรีย่อยมากกว่า 2 ไดเร็กทอรี line 17: [: 20150424-002813: unary operator expectedที่20150424-002813เป็นหนึ่งในรายชื่อไดเรกทอรี เปลือกที่ใช้คือ/bin/bash/. ในที่สุดฉันก็เปลี่ยนเป็นls "$destination" | tail -1
Christophe De Troyer

สวัสดี @ChristopheDeTroyer ฉันไม่สามารถสร้างปัญหาของคุณซ้ำได้ ในด้านของฉันออกในข้อผิดพลาดif [ ``ls -A my/dir`` ] bash: [: -A: binary operator expectedทดสอบกับ bash เวอร์ชัน 4.1.2 และ 4.2.53
olibre

1
ฉันถูกกระตุ้นให้แสดงความคิดเห็นเป็นหลักเนื่องจากการรับรู้ที่ไม่สอดคล้องกัน (เนื่องจาก-nตัวแปรอยู่ในพาดหัว แต่ไม่อยู่ในย่อหน้าด้านล่าง) ใช่ไม่เป็นไร
maxschlepzig

1
ผมใช้วิธีการแก้ปัญหาของคุณ -n ls: cannot access '/path': No such file or directoryยังภาพนิ่งสคริปต์ของฉันบ่นเกี่ยวกับเรื่องนี้ มีวิธีระงับข้อความนี้หรือไม่? ฉันอยากจะล้มเหลวอย่างเงียบ ๆ ที่นั่น
Freedo

48

เกี่ยวกับสิ่งต่อไปนี้:

if find /some/dir/ -maxdepth 0 -empty | read v; then echo "Empty dir"; fi

วิธีนี้ไม่จำเป็นต้องสร้างรายการเนื้อหาทั้งหมดของไดเร็กทอรี readเป็นทั้งยกเลิกการออกและทำให้การแสดงออกประเมินจริงเฉพาะเมื่อสิ่งที่อ่าน (เช่น/some/dir/พบว่าว่างเปล่าโดยfind)


3
หรือเพียงแค่find /some/dir/ -maxdepth 0 -empty -exec echo "huzzah" \;
doubleDown

5
+1 นี่เป็นทางออกที่สวยงามที่สุด ไม่เกี่ยวข้องกับการแยกวิเคราะห์lsเอาต์พุตและไม่อาศัยคุณลักษณะเชลล์ที่ไม่ใช่ค่าเริ่มต้น

7
อย่างไรก็ตามมันขึ้นอยู่กับความไม่ได้มาตรฐาน-maxdepthและ-emptyไพรมารี
chepner

21

ลอง:

if [ ! -z `ls /some/dir/*` ]; then echo "huzzah"; fi

สิ่งนี้ใช้ได้ผลสำหรับฉัน แต่ฉันไม่สามารถจัดรูปแบบข้อความ d * mn นี้ได้ !!! <br> ส่งออก tmp = /bin/ls <some_dir>/* 2> /dev/nullif [! -z "$ tmp"]; แล้วสะท้อนบางสิ่งบางอย่างอยู่ที่นั่น
AndrewStone

1
สำหรับ Bash idiots อย่างฉันถ้าคุณต้องการตรวจสอบตรงข้าม - ว่าไดเร็กทอรีว่าง - ใช้ if [-z ls /some/dir/*]; แล้วก้อง "huzzah"; fi
Chris Moschini

4
คุณสามารถใช้-nแทน! -z(ทั้งคู่เทียบเท่ากัน แต่ทำไมไม่ใช้รูปแบบที่สั้นกว่าเมื่อมีอยู่)
n.st

ด้วย ZSH ตัวอย่างนี้ทำให้เกิดข้อผิดพลาดแนวคิดคืออย่าให้เกิดข้อผิดพลาด ... BigGray% if [ ! -z ls / some / dir / * `]; แล้วก้อง "huzzah"; fi zsh: ไม่พบรายการที่ตรงกัน: / some / dir / * `
Hvisage

ไม่ได้ผลสำหรับฉันหากไม่มีเครื่องหมายคำพูดคู่ls...ใน bash
letmutx

15
# Works on hidden files, directories and regular files
### isEmpty()
# This function takes one parameter:
# $1 is the directory to check
# Echoes "huzzah" if the directory has files
function isEmpty(){
  if [ "$(ls -A $1)" ]; then
    echo "huzzah"
  else 
    echo "has no files"
  fi
}

15

ดูแลไดเรกทอรีที่มีไฟล์จำนวนมาก! อาจใช้เวลาสักครู่ในการประเมินไฟล์lsคำสั่ง

IMO ทางออกที่ดีที่สุดคือวิธีที่ใช้

find /some/dir/ -maxdepth 0 -empty


6

คุณสามารถเปรียบเทียบผลลัพธ์ของสิ่งนี้ได้หรือไม่?

 ls -A /some/dir | wc -l

4
# ตรวจสอบว่าไดเร็กทอรีมีไฟล์ที่ไม่ถูกซ่อนหรือไม่
#
# การใช้งาน: ถ้าว่างเปล่า "$ HOME"; แล้วก้อง "ยินดีต้อนรับกลับบ้าน"; Fi
#
มันว่างเปล่า() {
    สำหรับ _ief ใน $ 1 / *; ทำ
        ถ้า [-e "$ _ief"]; แล้วก็
            ผลตอบแทน 1
        Fi
    เสร็จแล้ว
    กลับ 0
}

หมายเหตุการใช้งานบางส่วน:

  • forห่วงหลีกเลี่ยงการโทรไปยังภายนอกlsกระบวนการ มันยังคงอ่านรายการไดเรกทอรีทั้งหมดเพียงครั้งเดียว สิ่งนี้สามารถปรับให้เหมาะสมได้โดยการเขียนโปรแกรม C ที่ใช้ readdir () อย่างชัดเจนเท่านั้น
  • test -eภายในห่วงจับกรณีของไดเรกทอรีที่ว่างเปล่าซึ่งในกรณีที่ตัวแปร_iefจะได้รับการกำหนดค่า "somedir / *" เฉพาะในกรณีที่ไฟล์นั้นมีอยู่ฟังก์ชันจะส่งคืน "nonempty"
  • ฟังก์ชันนี้จะทำงานในการใช้งาน POSIX ทั้งหมด แต่โปรดทราบว่า Solaris / bin / sh ไม่ได้อยู่ในหมวดหมู่นั้น ใช้testการดำเนินการไม่สนับสนุน-eธง

1
สิ่งนี้จะเพิกเฉยต่อ dotfiles ในไดเร็กทอรีหากdotglobไม่ได้ตั้งค่า -shopt -s dotglob
l0b0

4

สิ่งนี้บอกฉันว่าไดเร็กทอรีว่างหรือไม่หรือไม่จำนวนไฟล์ที่มีอยู่

directory="/some/dir"
number_of_files=$(ls -A $directory | wc -l)

if [ "$number_of_files" == "0" ]; then
    echo "directory $directory is empty"
else
    echo "directory $directory contains $number_of_files files"
fi

ใครช่วยอธิบายหน่อยได้ไหมว่าทำไมฉันถึงถูกลดคะแนน ถ้ากำลังเขียน craps Id 'อยากรู้ว่าทำไม;)
Daishi

1
ฉันไม่ได้ลงคะแนนสิ่งนี้ แต่เดาได้ว่าเป็นเพราะคุณกำลังแยกวิเคราะห์ผลลัพธ์ของls .
Toby Speight

บทความที่เชื่อมโยงไม่ชัดเจนหรือไม่ ในกรณีนี้โปรดส่งอีเมลถึงผู้เขียน (ไม่ใช่ฉัน)
Toby Speight

1
@TobySpeight ฉันเห็นประเด็น แต่ในกรณีนี้ฉันกำลังนับบรรทัดที่ไม่ได้ระบุ 'em ควรให้ผลลัพธ์ที่ผิดพลาดก็ต่อเมื่อชื่อไฟล์มีบรรทัดใหม่ และถ้าชื่อไฟล์มีบรรทัดใหม่สิ่งที่สำคัญกว่านั้นต้องมี f ** ked อยู่ที่ไหนสักแห่ง;)
Daishi

3

นี่อาจเป็นการตอบกลับที่ล่าช้า แต่นี่คือวิธีแก้ปัญหาที่ใช้ได้ผล บรรทัดนี้รับรู้เฉพาะการมีอยู่ของไฟล์เท่านั้น! จะไม่ให้ผลบวกปลอมหากมีไดเรกทอรีอยู่

if find /path/to/check/* -maxdepth 0 -type f | read
  then echo "Files Exist"
fi

2
dir_is_empty() {
   [ "${1##*/}" = "*" ]
}

if dir_is_empty /some/dir/* ; then
   echo "huzzah"
fi

สมมติว่าคุณไม่ได้มีไฟล์ชื่อ*เข้า/any/dir/you/checkก็ควรจะทำงานในbash dash posh busybox shและzshแต่ (สำหรับ zsh) unsetopt nomatchจำเป็นต้องใช้

การแสดงควรเทียบได้กับการlsใช้งาน*(glob) ฉันเดาว่าจะช้าในไดเร็กทอรีที่มีหลายโหนด (ของฉันที่/usr/binมีไฟล์มากกว่า 3,000 ไฟล์ก็ไม่ช้าขนาดนั้น) จะใช้หน่วยความจำอย่างน้อยเพียงพอที่จะจัดสรร dirs / ชื่อไฟล์ทั้งหมด (และอื่น ๆ ) เนื่องจากทั้งหมดถูกส่งผ่าน (แก้ไข) ไปยังฟังก์ชันเป็นอาร์กิวเมนต์บางเชลล์อาจมีข้อ จำกัด เกี่ยวกับจำนวนอาร์กิวเมนต์และ / หรือความยาวของอาร์กิวเมนต์

วิธีการแบบพกพาที่รวดเร็ว O (1) เป็นศูนย์ทรัพยากรเพื่อตรวจสอบว่าไดเรกทอรีว่างเปล่าจะดีหรือไม่

ปรับปรุง

เวอร์ชันด้านบนไม่ได้ระบุถึงไฟล์ / dirs ที่ซ่อนอยู่ในกรณีที่จำเป็นต้องมีการทดสอบเพิ่มเติมเช่นเทคนิคis_emptyจากRich's sh (POSIX shell) :

is_empty () (
cd "$1"
set -- .[!.]* ; test -f "$1" && return 1
set -- ..?* ; test -f "$1" && return 1
set -- * ; test -f "$1" && return 1
return 0 )

แต่ฉันคิดเกี่ยวกับสิ่งนี้แทน:

dir_is_empty() {
    [ "$(find "$1" -name "?*" | dd bs=$((${#1}+3)) count=1 2>/dev/null)" = "$1" ]
}

ความกังวลบางประการเกี่ยวกับการขีดทับความแตกต่างจากอาร์กิวเมนต์และผลลัพธ์ที่ค้นหาเมื่อ dir ว่างเปล่าและการขึ้นบรรทัดใหม่ต่อท้าย (แต่ควรจัดการได้ง่าย) น่าเศร้าในการbusybox shแสดงของฉันสิ่งที่น่าจะเป็นข้อบกพร่องบนfind -> ddไปป์โดยที่เอาต์พุตถูกตัดทอนแบบสุ่ม ( ถ้าฉันใช้catผลลัพธ์จะเหมือนกันเสมอดูเหมือนว่าจะddมีอาร์กิวเมนต์count)


ฉันชอบโซลูชันแบบพกพา ฉันมาเพื่อให้คำตอบเดียวกัน ฉันเพิ่งเขียนมันต่างออกไป (ส่งคืน 2 หากไม่ใช่ไดเร็กทอรี) นอกจากนี้โซลูชันแบบพกพาเหล่านี้ยังมีข้อได้เปรียบในการไม่เรียกโปรแกรมภายนอกใด ๆ ซึ่งอาจนับเป็นข้อดีสำหรับระบบที่มีข้อ จำกัด หรือระบบฝังตัว ฉันกังวลเพียงว่าการใช้ "()" อาจสร้างกระบวนการย่อยใหม่ (หรืออย่างน้อยก็บังคับให้คัดลอกสภาพแวดล้อมและสิ่งต่างๆแล้วเปลี่ยนกลับ) ลองดูที่นี้: is_empty () {_d = "$ {1: -.}"; [! -d "$ {_ d}"] && return 2; set - "$ {_ d}" / * "$ {_ d}" /. [!.]* "$ {_ d}" /..?*; ["$ { }" = "$ {_ d} / $ {_ d} /. [!.] * $ {_ d} /..?*"]; };
Diego Augusto Molina

@DiegoAugustoMolina เมื่อเร็ว ๆ นี้ในโปรเจ็กต์ฉันต้องทำการทดสอบนี้อีกครั้งหากไดเร็กทอรีว่างในตอนแรกฉันใช้ python จากนั้นตั้งแต่ฉันติดตั้ง python ในทางปฏิบัติฉันจึงทำการทดสอบใน c การใช้งานนั้นสุดขั้ว ความซ้ำซากฉันสงสัยว่าทำไมจึงไม่ถูกเพิ่มเป็นการทดสอบหรือเป็นคำสั่งแบบสแตนด์อะโลน
Alex

1
เมื่อเร็ว ๆ นี้ฉันก็ต้องการวิธีแก้ไขสำหรับปัญหานี้สำหรับระบบที่มีข้อ จำกัด (จริงๆ) ฉันยังปรับโค้ดก่อนหน้าให้เหมาะสมเล็กน้อยเพื่อไม่ให้ใช้ตัวแปรพิเศษเลย ซับหนึ่งที่ดูแฮ็กและน่าเกลียด แต่ก็เยี่ยมมาก รับใช้ตัวเอง:is_empty(){ [ ! -d "${1}" ] && return 2;set -- "${1}" "${1}"/* "${1}"/.[!.]* "${1}"/..?*;[ "${*}" = "${1} ${1}/* ${1}/.[!.]* ${1}/..?*" ]; };
Diego Augusto Molina

2

ZSH

ฉันรู้ว่าคำถามถูกทำเครื่องหมายสำหรับทุบตี แต่สำหรับการอ้างอิงสำหรับผู้ใช้zsh :

ทดสอบไดเร็กทอรีที่ไม่ว่างเปล่า

วิธีตรวจสอบว่าfooว่างเปล่า:

$ for i in foo(NF) ; do ... ; done

โดยที่ถ้าfooไม่ว่างรหัสในforบล็อกจะถูกเรียกใช้งาน

ทดสอบไดเร็กทอรีว่าง

วิธีตรวจสอบว่าfooว่างเปล่า:

$ for i in foo(N/^F) ; do ... ; done

โดยที่ถ้าfooว่างรหัสในforบล็อกจะถูกเรียกใช้งาน

หมายเหตุ

เราไม่จำเป็นต้องอ้างถึงไดเร็กทอรีfooด้านบน แต่เราสามารถทำได้หากต้องการ:

$ for i in 'some directory!'(NF) ; do ... ; done

นอกจากนี้เรายังสามารถทดสอบมากกว่าหนึ่งวัตถุแม้ว่าจะไม่ใช่ไดเร็กทอรี:

$ mkdir X     # empty directory
$ touch f     # regular file
$ for i in X(N/^F) f(N/^F) ; do echo $i ; done  # echo empty directories
X

สิ่งที่ไม่ใช่ไดเร็กทอรีจะถูกละเว้น

พิเศษ

เนื่องจากเรากำลัง globbing เราสามารถใช้ glob (หรือการขยายตัวรั้ง):

$ mkdir X X1 X2 Y Y1 Y2 Z
$ touch Xf                    # create regular file
$ touch X1/f                  # directory X1 is not empty
$ touch Y1/.f                 # directory Y1 is not empty
$ ls -F                       # list all objects
X/ X1/ X2/ Xf Y/ Y1/ Y2/ Z/
$ for i in {X,Y}*(N/^F); do printf "$i "; done; echo  # print empty directories
X X2 Y Y2

นอกจากนี้เรายังตรวจสอบวัตถุที่อยู่ในอาร์เรย์ได้อีกด้วย ด้วยไดเร็กทอรีด้านบนตัวอย่างเช่น:

$ ls -F                       # list all objects
X/ X1/ X2/ Xf Y/ Y1/ Y2/ Z/
$ arr=(*)                     # place objects into array "arr"
$ for i in ${^arr}(N/^F); do printf "$i "; done; echo
X X2 Y Y2 Z

ดังนั้นเราสามารถทดสอบวัตถุที่อาจตั้งค่าไว้แล้วในพารามิเตอร์อาร์เรย์

สังเกตว่าโค้ดในforบล็อกนั้นถูกเรียกใช้อย่างชัดเจนในทุกไดเร็กทอรี หากไม่เป็นที่ต้องการคุณสามารถเติมพารามิเตอร์อาร์เรย์จากนั้นดำเนินการกับพารามิเตอร์นั้น:

$ for i in *(NF) ; do full_directories+=($i) ; done
$ do_something $full_directories

คำอธิบาย

สำหรับผู้ใช้ zsh จะมี(F)glob qualifier (ดูman zshexpn) ซึ่งตรงกับไดเร็กทอรี "เต็ม" (ไม่ว่างเปล่า):

$ mkdir X Y
$ touch Y/.f        # Y is now not empty
$ touch f           # create a regular file
$ ls -dF *          # list everything in the current directory
f X/ Y/
$ ls -dF *(F)       # will list only "full" directories
Y/

Qualifier (F)แสดงรายการอ็อบเจ็กต์ที่ตรงกัน: คือไดเร็กทอรี AND ไม่ว่างเปล่า ดังนั้นการ(^F)จับคู่: ไม่ใช่ไดเรกทอรีหรือว่างเปล่า ดังนั้น(^F)เพียงอย่างเดียวก็จะแสดงรายการไฟล์ปกติเช่น ดังนั้นตามที่อธิบายไว้ในzshexpman page เราจึงต้องการ(/)glob qualifier ซึ่งแสดงเฉพาะไดเร็กทอรี:

$ mkdir X Y Z
$ touch X/f Y/.f    # directories X and Y now not empty
$ for i in *(/^F) ; do echo $i ; done
Z

ดังนั้นในการตรวจสอบว่าไดเร็กทอรีที่ระบุว่างเปล่าคุณจึงสามารถรัน:

$ mkdir X
$ for i in X(/^F) ; do echo $i ; done ; echo "finished"
X
finished

และเพื่อให้แน่ใจว่าจะไม่จับไดเร็กทอรีที่ไม่ว่างเปล่า:

$ mkdir Y
$ touch Y/.f
$ for i in Y(/^F) ; do echo $i ; done ; echo "finished"
zsh: no matches found: Y(/^F)
finished

อ๊ะ! เนื่องจากYไม่ใช่ช่องว่าง zsh จึงไม่พบรายการที่ตรงกันสำหรับ(/^F)("ไดเร็กทอรีที่ว่าง") จึงพ่นข้อความแสดงข้อผิดพลาดที่แจ้งว่าไม่พบข้อมูลที่ตรงกันสำหรับ glob ดังนั้นเราจึงจำเป็นต้องระงับข้อความแสดงข้อผิดพลาดที่เป็นไปได้เหล่านี้ด้วย(N)glob qualifier:

$ mkdir Y
$ touch Y/.f
$ for i in Y(N/^F) ; do echo $i ; done ; echo "finished"
finished

ดังนั้นสำหรับไดเร็กทอรีว่างเราจำเป็นต้องมีคุณสมบัติ(N/^F)ซึ่งคุณสามารถอ่านได้ว่า: "อย่าเตือนฉันเกี่ยวกับความล้มเหลวไดเร็กทอรีที่ไม่เต็ม"

ในทำนองเดียวกันสำหรับไดเรกทอรีที่ไม่ว่างเปล่าเราจำเป็นต้องมีคุณสมบัติ(NF)ซึ่งเราสามารถอ่านได้ในทำนองเดียวกันว่า: "อย่าเตือนฉันเกี่ยวกับความล้มเหลวไดเรกทอรีแบบเต็ม"


1

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

หมายเหตุจากหน้านั้น:

อย่าพยายามแยกวิเคราะห์เอาต์พุต ls แม้แต่โซลูชัน ls -A ก็สามารถพังได้ (เช่นใน HP-UX หากคุณเป็นรูท ls -A จะตรงข้ามกับสิ่งที่ทำถ้าคุณไม่ได้รูท - และไม่ฉันไม่สามารถสร้างสิ่งที่เหลือเชื่อได้ โง่).

ในความเป็นจริงเราอาจต้องการหลีกเลี่ยงคำถามโดยตรงโดยสิ้นเชิง โดยปกติผู้คนต้องการทราบว่าไดเร็กทอรีว่างหรือไม่เนื่องจากต้องการทำบางสิ่งที่เกี่ยวข้องกับไฟล์ในนั้นเป็นต้นมองไปที่คำถามที่ใหญ่กว่า ตัวอย่างเช่นหนึ่งในตัวอย่างที่ใช้ค้นหาเหล่านี้อาจเป็นวิธีแก้ปัญหาที่เหมาะสม:

   # Bourne
   find "$somedir" -type f -exec echo Found unexpected file {} \;
   find "$somedir" -maxdepth 0 -empty -exec echo {} is empty. \;  # GNU/BSD
   find "$somedir" -type d -empty -exec cp /my/configfile {} \;   # GNU/BSD

โดยทั่วไปสิ่งที่จำเป็นจริงๆคือสิ่งนี้:

   # Bourne
   for f in ./*.mpg; do
        test -f "$f" || continue
        mympgviewer "$f"
    done

กล่าวอีกนัยหนึ่งผู้ที่ถามคำถามอาจคิดว่าจำเป็นต้องมีการทดสอบไดเร็กทอรีว่างอย่างชัดเจนเพื่อหลีกเลี่ยงข้อความแสดงข้อผิดพลาดเช่น mympgviewer: ./*.mpg: ไม่มีไฟล์หรือไดเร็กทอรีดังกล่าวในความเป็นจริงไม่จำเป็นต้องมีการทดสอบดังกล่าว



1

คำใบ้ (หรือหลายอย่าง) จากคำตอบของ olibre ฉันชอบฟังก์ชั่น Bash:

function isEmptyDir {
  [ -d $1 -a -n "$( find $1 -prune -empty 2>/dev/null )" ]
}

เพราะในขณะที่มันสร้างหนึ่ง subshell มันใกล้เคียงกับโซลูชัน O (1) เท่าที่ฉันจะจินตนาการได้และตั้งชื่อให้มันทำให้อ่านได้ จากนั้นฉันสามารถเขียน

if isEmptyDir somedir
then
  echo somedir is an empty directory
else
  echo somedir does not exist, is not a dir, is unreadable, or is  not empty
fi

สำหรับ O (1) มีกรณีผิดปกติ: หากไดเร็กทอรีขนาดใหญ่มีทั้งหมดหรือทั้งหมดยกเว้นรายการสุดท้ายที่ถูกลบออก "find" อาจต้องอ่านข้อมูลทั้งหมดเพื่อพิจารณาว่าว่างหรือไม่ ฉันเชื่อว่าประสิทธิภาพที่คาดหวังคือ O (1) แต่กรณีที่แย่ที่สุดคือขนาดไดเร็กทอรีเชิงเส้น ฉันไม่ได้วัดสิ่งนี้


0

จนถึงตอนนี้ฉันยังไม่เห็นคำตอบที่ใช้ grep ซึ่งฉันคิดว่าจะให้คำตอบที่ง่ายกว่านี้ (โดยมีสัญลักษณ์แปลก ๆ ไม่มากนัก!) นี่คือวิธีที่ฉันจะตรวจสอบว่ามีไฟล์ใดอยู่ในไดเร็กทอรีโดยใช้ bourne shell:

สิ่งนี้ส่งคืนจำนวนไฟล์ในไดเร็กทอรี:

ls -l <directory> | egrep -c "^-"

คุณสามารถกรอกเส้นทางไดเร็กทอรีที่เขียนไดเร็กทอรี ครึ่งแรกของไปป์จะทำให้แน่ใจว่าอักขระตัวแรกของเอาต์พุตคือ "-" สำหรับแต่ละไฟล์ จากนั้น egrep จะนับจำนวนบรรทัดที่ขึ้นต้นด้วยสัญลักษณ์นั้นโดยใช้นิพจน์ทั่วไป ตอนนี้สิ่งที่คุณต้องทำคือเก็บหมายเลขที่คุณได้รับและเปรียบเทียบโดยใช้ backquotes เช่น:

 #!/bin/sh 
 fileNum=`ls -l <directory> | egrep -c "^-"`  
 if [ $fileNum == x ] 
 then  
 #do what you want to do
 fi

x เป็นตัวแปรที่คุณเลือก


0

ฉันได้ทำสิ่งที่ผสมลูกพรุนและคำตอบสุดท้าย

find "$some_dir" -prune -empty -type d | read && echo empty || echo "not empty"

ที่ใช้ได้กับเส้นทางที่มีช่องว่างด้วย



0

ฉันจะไปเพื่อfind:

if [ -z "$(find $dir -maxdepth 1 -type f)" ]; then
    echo "$dir has NO files"
else
    echo "$dir has files"

การตรวจสอบผลลัพธ์ของการค้นหาเฉพาะไฟล์ในไดเร็กทอรีโดยไม่ต้องผ่านไดเร็กทอรีย่อย จากนั้นจะตรวจสอบผลลัพธ์โดยใช้-zตัวเลือกที่นำมาจากman test:

   -z STRING
          the length of STRING is zero

ดูผลลัพธ์บางอย่าง:

$ mkdir aaa
$ dir="aaa"

ผบ.

$ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty"
empty

เพียงแค่เข้าไปในนั้น:

$ mkdir aaa/bbb
$ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty"
empty

ไฟล์ในไดเร็กทอรี:

$ touch aaa/myfile
$ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty"
$ rm aaa/myfile 

ไฟล์ในไดเร็กทอรีย่อย:

$ touch aaa/bbb/another_file
$ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty"
empty

0

ด้วยวิธีแก้ปัญหาบางอย่างฉันสามารถหาวิธีง่ายๆในการค้นหาว่ามีไฟล์อยู่ในไดเร็กทอรีหรือไม่ สิ่งนี้สามารถขยายได้มากขึ้นด้วยคำสั่ง grep เพื่อตรวจสอบไฟล์. xml หรือ. txt โดยเฉพาะเป็นต้นเช่น:ls /some/dir | grep xml | wc -l | grep -w "0"

#!/bin/bash
if ([ $(ls /some/dir | wc -l  | grep -w "0") ])
    then
        echo 'No files'
    else
        echo 'Found files'
fi

-1
if ls /some/dir/* >/dev/null 2>&1 ; then echo "huzzah"; fi;

ฉันชอบอันนี้เพราะไม่มีเครื่องหมายคำพูดหรือวงเล็บที่ประกอบคำสั่ง
Dave Webb

ระวังอย่าใช้สิ่งนี้หากคุณตั้งค่าไว้nullglobเพราะlsคำสั่งจะสำเร็จ
Steve Kehlet

จะไม่ทำงานในทุกสภาพแวดล้อมในกรณีที่ไดเร็กทอรีมีไฟล์ dot
Diego Augusto Molina

-1

เพื่อทดสอบไดเร็กทอรีเป้าหมายเฉพาะ

if [ -d $target_dir ]; then
    ls_contents=$(ls -1 $target_dir | xargs); 
    if [ ! -z "$ls_contents" -a "$ls_contents" != "" ]; then
        echo "is not empty";
    else
        echo "is empty";
    fi;
else
    echo "directory does not exist";
fi;

-1

ลองใช้คำสั่งค้นหา ระบุไดเร็กทอรีฮาร์ดโค้ดหรือเป็นอาร์กิวเมนต์ จากนั้นเริ่มค้นหาเพื่อค้นหาไฟล์ทั้งหมดภายในไดเร็กทอรี ตรวจสอบว่าผลตอบแทนของการค้นหาเป็นโมฆะหรือไม่ สะท้อนข้อมูลของการค้นหา

#!/bin/bash

_DIR="/home/user/test/"
#_DIR=$1
_FIND=$(find $_DIR -type f )
if [ -n "$_FIND" ]
then
   echo -e "$_DIR contains files or subdirs with files \n\n "
   echo "$_FIND"
else
echo "empty (or does not exist)"
fi

หากไดเร็กทอรีมีไดเร็กทอรีว่างหรือไฟล์ที่ไม่ปกติ (ซ็อกเก็ต, อุปกรณ์ถ่าน, ลิงก์สัญลักษณ์ ฯลฯ ) อยู่ภายในสิ่งนี้จะไม่ทำงาน ไดเร็กทอรีจะถูกรายงานว่าว่างเปล่า
Diego Augusto Molina

@DiegoAugustoMolina ถ้าฉันเข้าใจอย่างถูกต้องในคำถามคือเรากำลังต้องการตรวจสอบว่ามีไฟล์อยู่หรือไม่ (เป็นไฟล์ในตัวอักษร) ที่ใช้อาร์กิวเมนต์เหตุผล -f แต่ความคิดเห็นของคุณยังคงเป็นจริง
igiannak

-2

ฉันไม่ชอบls - Aวิธีแก้ปัญหาที่โพสต์ เป็นไปได้มากว่าคุณต้องการทดสอบว่าไดเร็กทอรีว่างเปล่าเพราะคุณไม่ต้องการลบ ต่อไปนี้ทำเช่นนั้น อย่างไรก็ตามหากคุณต้องการบันทึกไฟล์เปล่าอย่างแน่นอนการลบและสร้างใหม่นั้นเร็วกว่าการแสดงรายการไฟล์ที่ไม่มีที่สิ้นสุดหรือไม่?

นี่น่าจะใช้ได้ ...

if !  rmdir ${target}
then
    echo "not empty"
else
    echo "empty"
    mkdir ${target}
fi

4
${target}/..นี้จะไม่ทำงานหากผู้ใช้ไม่มีสิทธิ์ในการเขียนไป
Jens

เป็นเพียงความคิดที่ไม่ดีในการทดสอบการทำลายล้าง เหนือสิ่งอื่นใดมันแนะนำเงื่อนไขการแข่งขัน
4dummies

-2

ทำงานได้ดีสำหรับฉันสิ่งนี้ (เมื่อมีผบ.):

some_dir="/some/dir with whitespace & other characters/"
if find "`echo "$some_dir"`" -maxdepth 0 -empty | read v; then echo "Empty dir"; fi

ด้วยการตรวจสอบแบบเต็ม:

if [ -d "$some_dir" ]; then
  if find "`echo "$some_dir"`" -maxdepth 0 -empty | read v; then echo "Empty dir"; else "Dir is NOT empty" fi
fi
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.