ฉันต้องการค้นหาไดเรกทอรีย่อยของไดเรกทอรีปัจจุบันซึ่ง (นั่นคือไดเรกทอรีย่อย) มีไฟล์ปกติอย่างน้อย 2 ไฟล์
ฉันไม่สนใจไดเรกทอรีที่มีไฟล์น้อยกว่า 2 ไฟล์และไม่ได้อยู่ในไดเรกทอรีที่มีไดเรกทอรีย่อยเท่านั้น
ฉันต้องการค้นหาไดเรกทอรีย่อยของไดเรกทอรีปัจจุบันซึ่ง (นั่นคือไดเรกทอรีย่อย) มีไฟล์ปกติอย่างน้อย 2 ไฟล์
ฉันไม่สนใจไดเรกทอรีที่มีไฟล์น้อยกว่า 2 ไฟล์และไม่ได้อยู่ในไดเรกทอรีที่มีไดเรกทอรีย่อยเท่านั้น
คำตอบ:
นี่คือวิธีการที่แตกต่างกันอย่างสมบูรณ์ขึ้นอยู่กับ GNU และfind
uniq
สิ่งนี้เร็วกว่าและเป็นมิตรกับ CPU มากกว่าคำตอบโดยขึ้นอยู่กับการดำเนินการคำสั่งเชลล์ที่นับจำนวนไฟล์สำหรับแต่ละไดเรกทอรีที่พบ
find . -type f -printf '%h\n' | sort | uniq -d
find
คำสั่งพิมพ์ไดเรกทอรีของไฟล์ทั้งหมดในลำดับชั้นและuniq
แสดงเฉพาะไดเรกทอรีที่ปรากฏอย่างน้อยสองครั้ง
-printf '%h\0' | sort -z | uniq -zd | xargs -r0 ...
find . -type d \
-exec sh -c 'c=0; for n in "$1"/*; do [ -f "$n" ] && [ ! -h "$n" ] && c=$(( c + 1 )); done; [ "$c" -ge 2 ]' sh {} ';' \
-print
นี่จะค้นหาชื่อทั้งหมดในหรือภายใต้ไดเรกทอรีปัจจุบันแล้วกรองชื่อทั้งหมดที่ไม่ใช่ชื่อของไดเรกทอรี
ชื่อไดเรกทอรีที่เหลือจะถูกมอบให้กับสคริปต์สั้น ๆ นี้:
c=0
for n in "$1"/*; do
[ -f "$n" ] && [ ! -h "$n" ] && c=$(( c + 1 ))
done
[ "$c" -ge 2 ]
สคริปต์นี้จะนับจำนวนไฟล์ปกติ (ข้ามลิงก์สัญลักษณ์) ในไดเรกทอรีที่กำหนดเป็นอาร์กิวเมนต์บรรทัดคำสั่งแรก (จากfind
) คำสั่งสุดท้ายในสคริปต์คือการทดสอบเพื่อดูว่าการนับเป็น 2 หรือมากกว่า ผลลัพธ์ของการทดสอบนี้คือค่าส่งคืน (สถานะออก) ของสคริปต์
หากการทดสอบสำเร็จ-print
จะทำให้find
พิมพ์เส้นทางไปยังไดเรกทอรี
หากต้องการพิจารณาไฟล์ที่ซ่อนอยู่ (ไฟล์ที่ชื่อขึ้นต้นด้วยจุด) ให้เปลี่ยนsh -c
สคริปต์จากคำพูด
for n in "$1"/*; do
ถึง
for n in "$1"/* "$1"/.*; do
การทดสอบ:
$ tree
.
`-- test
|-- a
|-- dir1
| |-- a
| |-- b
| `-- c
`-- dir2
|-- dira
|-- dirb
| |-- file-1
| `-- file-2
`-- dirc
6 directories, 6 files
$ find . -type d -exec sh -c 'c=0; for n in "$1"/*; do [ -f "$n" ] && [ ! -h "$n" ] && c=$(( c + 1 )); done; [ "$c" -ge 2 ]' sh {} ';' -print
./test/dir1
./test/dir2/dirb
[ "" -ge 2 ]
เป็นการทดสอบที่ถูกต้อง
dash
, bash --posix
และtest
จอแสดงผลทุกข้อผิดพลาดและออกมี 2 (คือ "เกิดข้อผิดพลาด")
ksh
กำลังทำงานsh
อยู่ จะแก้ไขทันที ขอบคุณสำหรับ poking ที่ฉัน! :-)
[ -f ... ]
ลิงก์ที่เป็นสัญลักษณ์ คุณควรเพิ่มการทดสอบเพื่อกำจัดเนื่องจากคำถามระบุว่าควรนับเฉพาะไฟล์ปกติเท่านั้น
ด้วยความช่วยเหลือของคำตอบของ Gillesในเรื่องSUและการย้อนกลับและการดัดแปลงบางอย่างนี่คือสิ่งที่คุณต้องการ
find . -type d -exec sh -c 'set -- "$1"/*;X=0;
for args; do [ -f "$args" ] && X=$((X+1)) ;done; [ "$X" -gt 1 ] ' _ {} \; -print
ต้นไม้ไดเรกทอรี
.
├── test
│ ├── dir1
│ │ ├── a
│ │ ├── b
│ │ └── c
│ ├── dir2
│ │ ├── dira
│ │ │ └── a file\012with\012multiple\012line
│ │ ├── dirb
│ │ │ ├── file-1
│ │ │ └── file-2
│ │ └── dirc
│ ├── diraa
│ ├── dirbb
│ ├── dircc
│ └── x
│ └── x1
│ └── x2
└── test2
├── dir3
└── dir4
ผลลัพธ์:
./test
./test/dir1
./test/dir2/dirb
test
และdir2
ไดเรกทอรีในการตั้งค่าการทดสอบของฉัน (ดูคำตอบของฉัน)
test/x1
และtest/x2
เป็นไฟล์เช่น ... $1
และ$2
จะเป็นไดเรกทอรีสำหรับtest
และไดเรกทอรีจะพลาด
อีกวิธีfind
+ wc
:
find path/currdir -maxdepth 1 -type d ! -empty ! -path "path/currdir" \
-exec sh -c 'count=$(find "$1" -maxdepth 1 -type f | wc -l); [ $count -ge 2 ]' _ {} \; -print
path/currdir
- พา ธ ไปยังไดเรกทอรีปัจจุบันของคุณ
-maxdepth 1
- พิจารณาเฉพาะโฟลเดอร์ย่อยของเด็กโดยตรง
! -empty
- ละเว้นโฟลเดอร์ย่อยที่ว่างเปล่า
! -path "path/currdir"
- ละเว้นเส้นทางไดเรกทอรีปัจจุบัน
count=$(find "$1" -maxdepth 1 -type f | wc -l)
- count
ถูกกำหนดด้วยจำนวนไฟล์สำหรับแต่ละโฟลเดอร์ย่อยที่พบ
[ $count -ge 2 ] ... -print
- พิมพ์ชื่อ / พา ธ ของโฟลเดอร์ย่อยที่มีไฟล์ปกติอย่างน้อย 2 ไฟล์
find
คุณไม่ควรแยกการส่งออกของ ในกรณีนี้เนื่องจาก GNUfind
จะรวมชื่อไดเรกทอรีที่มีอักขระที่ไม่สามารถพิมพ์ได้ในภาษาปัจจุบัน (เช่น "ä" ในภาษา C) ดูเพิ่มเติมที่unix.stackexchange.com/questions/321697/…