ฉันมีโฟลเดอร์ที่มีไดเรกทอรีและไฟล์บางไฟล์ (บางไฟล์ถูกซ่อนอยู่เริ่มต้นด้วยจุด)
for d in *; do
echo $d
done
จะวนซ้ำไฟล์ทั้งหมด แต่ฉันต้องการวนซ้ำผ่านไดเรกทอรีเท่านั้น ฉันจะทำอย่างไร
ฉันมีโฟลเดอร์ที่มีไดเรกทอรีและไฟล์บางไฟล์ (บางไฟล์ถูกซ่อนอยู่เริ่มต้นด้วยจุด)
for d in *; do
echo $d
done
จะวนซ้ำไฟล์ทั้งหมด แต่ฉันต้องการวนซ้ำผ่านไดเรกทอรีเท่านั้น ฉันจะทำอย่างไร
คำตอบ:
คุณสามารถระบุเครื่องหมายทับที่ท้ายเพื่อจับคู่ไดเรกทอรีเท่านั้น:
for d in */ ; do
echo "$d"
done
[[ -L $d ]]
ว่า $ d เป็นลิงก์สัญลักษณ์หรือไม่
set -P
มีผลกับคำสั่งที่เปลี่ยนไดเรกทอรีเท่านั้น sprunge.us/TNac
[[ -L "$f" ]]
จะไม่รวมลิงก์ในกรณีนี้ด้วย*/
คุณจะต้องตัดเครื่องหมายทับต่อท้ายด้วย[[ -L "${f%/}" ]]
(ดูทดสอบการเชื่อมโยงด้วยเครื่องหมายทับ )
คุณสามารถทดสอบด้วย-d
:
for f in *; do
if [ -d "$f" ]; then
# $f is a directory
fi
done
if [[ -d "$f" && ! -L "$f" ]]
จะไม่รวม
if [[ "$f" = "*" ]]; then continue; fi
ระวังวิธีแก้ปัญหาของ choroba แม้ว่าจะสวยงาม แต่ก็สามารถล้วงเอาพฤติกรรมที่ไม่คาดคิดได้หากไม่มีไดเรกทอรีอยู่ในไดเรกทอรีปัจจุบัน ในสถานะนี้แทนที่จะข้ามfor
ลูป bash จะเรียกใช้ลูปหนึ่งครั้งโดยที่d
เท่ากับ*/
:
#!/usr/bin/env bash
for d in */; do
# Will print */ if no directories are available
echo $d
done
ฉันขอแนะนำให้ใช้สิ่งต่อไปนี้เพื่อป้องกันกรณีนี้:
#!/usr/bin/env bash
for f in *; do
if [ -d ${f} ]; then
# Will not run if no directories are available
echo $f
fi
done
รหัสนี้จะวนลูปผ่านไฟล์ทั้งหมดในไดเรกทอรีปัจจุบันตรวจสอบว่าf
เป็นไดเรกทอรีจากนั้นสะท้อนf
ถ้าเงื่อนไขส่งคืนจริง หากf
มีค่าเท่ากับ*/
, echo $f
จะไม่ดำเนินการ
shopt -s nullglob
ง่ายมากที่จะ
หากคุณต้องการเลือกไฟล์ที่เฉพาะเจาะจงมากกว่าไดเรกทอรีที่ใช้find
และส่งไปที่while read
:
shopt -s dotglob
find * -prune -type d | while IFS= read -r d; do
echo "$d"
done
ใช้shopt -u dotglob
เพื่อแยกไดเรกทอรีที่ซ่อนอยู่ (หรือsetopt dotglob
/ unsetopt dotglob
ใน zsh)
IFS=
เพื่อหลีกเลี่ยงการแยกชื่อไฟล์ที่มีหนึ่งใน$IFS
ตัวอย่างเช่น:'a b'
ดูAsymLabs คำตอบด้านล่างสำหรับfind
ตัวเลือกเพิ่มเติม
แก้ไข:
ในกรณีที่คุณต้องการสร้างค่าการออกจากภายในลูป while คุณสามารถหลีกเลี่ยงการแบ่งย่อยพิเศษด้วยเคล็ดลับนี้:
while IFS= read -r d; do
if [ "$d" == "something" ]; then exit 1; fi
done < <(find * -prune -type d)
คุณสามารถใช้ทุบตีบริสุทธิ์สำหรับสิ่งนั้น แต่ควรใช้ find:
find . -maxdepth 1 -type d -exec echo {} \;
(ค้นหาเพิ่มเติมจะรวมไดเรกทอรีที่ซ่อนอยู่)
shopt -s dotglob
สำหรับการbash
ที่จะรวมไดเรกทอรีที่ซ่อนอยู่ .
ขอแสดงยังจะรวมถึง โปรดทราบด้วยว่า-maxdepth
ไม่ใช่ตัวเลือกมาตรฐาน ( -prune
คือ)
dotglob
ตัวเลือกที่น่าสนใจ แต่เฉพาะกับการใช้งานของdotglob
จะรวมถึงไดเรกทอรีที่ซ่อนอยู่ (และ dir ปัจจุบันเช่นกัน)*
find .
สิ่งนี้จะทำเพื่อค้นหาทั้งไดเรกทอรีที่มองเห็นและซ่อนอยู่ภายในไดเรกทอรีทำงานปัจจุบันไม่รวมไดเรกทอรีราก:
การวนซ้ำไดเรกทอรีต่างๆ:
find -path './*' -prune -type d
เพื่อรวม symlink ในผลลัพธ์:
find -L -path './*' -prune -type d
ทำบางสิ่งบางอย่างกับแต่ละไดเรกทอรี (ยกเว้น symlink):
find -path './*' -prune -type d -print0 | xargs -0 <cmds>
เพื่อแยกไดเรกทอรีที่ซ่อนอยู่:
find -path './[^.]*' -prune -type d
เพื่อดำเนินการหลายคำสั่งในค่าที่ส่งคืน (ตัวอย่างที่มีการวางแผนอย่างมาก):
find -path './[^.]*' -prune -type d -print0 | xargs -0 -I '{}' sh -c \
"printf 'first: %-40s' '{}'; printf 'second: %s\n' '{}'"
แทน 'sh -c' ยังสามารถใช้ 'bash -c' เป็นต้น
... -print0 | xargs -0 ...
ถ้าคุณไม่ทราบว่าชื่อที่แน่นอนคืออะไร
find * | while read file; do ...
คุณสามารถวนซ้ำไดเรกทอรีทั้งหมดรวมถึงไดเรกทอรีที่ซ่อนอยู่ (ขึ้นต้นด้วยจุด) ในหนึ่งบรรทัดและหลายคำสั่งด้วย:
for file in */ .*/ ; do echo "$file is a directory"; done
หากคุณต้องการยกเว้นลิงก์:
for file in *; do
if [[ -d "$file" && ! -L "$file" ]]; then
echo "$file is a directory";
fi;
done
หมายเหตุ: การใช้รายการ*/ .*/
ทำงานในทุบตี แต่ยังแสดงโฟลเดอร์.
และ..
ในขณะที่ zsh มันจะไม่แสดงสิ่งเหล่านี้ แต่โยนข้อผิดพลาดหากไม่มีไฟล์ที่ซ่อนอยู่ในโฟลเดอร์
เวอร์ชันที่สะอาดกว่าซึ่งจะรวมไดเรกทอรีที่ซ่อนอยู่และไม่รวม .. / จะอยู่ในตัวเลือก dotglob:
shopt -s dotglob
for file in */ ; do echo "$file is a directory"; done
(หรือเป็นsetopt dotglob
zsh)
คุณสามารถยกเลิกการตั้งค่า dotglob ด้วย
shopt -u dotglob
ซึ่งจะรวมถึงเส้นทางที่สมบูรณ์ในแต่ละไดเรกทอรีในรายการ:
for i in $(find $PWD -maxdepth 1 -type d); do echo $i; done
ใช้find
กับ-exec
เพื่อวนซ้ำไดเรกทอรีและเรียกใช้ฟังก์ชันในตัวเลือก exec:
dosomething () {
echo "doing something with $1"
}
export -f dosomething
find -path './*' -prune -type d -exec bash -c 'dosomething "$0"' {} \;
ใช้shopt -s dotglob
หรือ shopt -u dotglob
เพื่อรวม / แยกไดเรกทอรีที่ซ่อนอยู่
รายการนี้แสดงไดเรกทอรีทั้งหมดพร้อมกับจำนวนไดเรกทอรีย่อยในเส้นทางที่กำหนด:
for directory in */ ; do D=$(readlink -f "$directory") ; echo $D = $(find "$D" -mindepth 1 -type d | wc -l) ; done
ls -d */ | while read d
do
echo $d
done
This
is
one
directory
with
spaces
in
the
name
- แต่ได้รับการแยกวิเคราะห์เป็นหลายรายการ
ls -l | grep ^d
หรือ:
ll | grep ^d
คุณอาจตั้งเป็นนามแฝง
ls
คำตอบที่ใช้เล็กน้อยนี้ซึ่งแสดงลิสต์ของไดเรกทอรี
ls
: mywiki.wooledge.org/ParsingLs