คำตอบนี้มีคำตอบสำหรับไฟล์ทุกประเภท ด้วยการขึ้นบรรทัดใหม่หรือช่องว่าง
มีวิธีแก้ปัญหาสำหรับการทุบตีเมื่อเร็ว ๆ นี้เช่นเดียวกับทุบตีโบราณและแม้กระทั่งเปลือกหอย POSIX เก่า
ต้นไม้ที่แสดงด้านล่างในคำตอบนี้[1]ใช้สำหรับการทดสอบ
เลือก
select
การทำงานกับอาร์เรย์ทำได้ง่าย:
$ dir='deep/inside/a/dir'
$ arr=( "$dir"/* )
$ select var in "${arr[@]}"; do echo "$var"; break; done
หรือด้วยพารามิเตอร์ตำแหน่ง:
$ set -- "$dir"/*
$ select var; do echo "$var"; break; done
ดังนั้นปัญหาที่แท้จริงคือการได้รับ "รายการไฟล์" (คั่นอย่างถูกต้อง) ภายในอาเรย์หรือภายในพารามิเตอร์ตำแหน่ง อ่านต่อไป
ทุบตี
ฉันไม่เห็นปัญหาที่คุณรายงานด้วยการทุบตี Bash สามารถค้นหาภายในไดเรกทอรีที่กำหนด:
$ dir='deep/inside/a/dir'
$ printf '<%s>\n' "$dir"/*
<deep/inside/a/dir/directory>
<deep/inside/a/dir/file>
<deep/inside/a/dir/file name>
<deep/inside/a/dir/file with a
newline>
<deep/inside/a/dir/zz last file>
หรือถ้าคุณชอบวง:
$ set -- "$dir"/*
$ for f; do printf '<%s>\n' "$f"; done
<deep/inside/a/dir/directory>
<deep/inside/a/dir/file>
<deep/inside/a/dir/file name>
<deep/inside/a/dir/file with a
newline>
<deep/inside/a/dir/zz last file>
โปรดทราบว่าไวยากรณ์ข้างต้นจะทำงานอย่างถูกต้องกับเชลล์ (สมเหตุสมผล) ใด ๆ (ไม่ใช่ csh อย่างน้อย)
ข้อ จำกัด เพียงอย่างเดียวที่ไวยากรณ์ข้างต้นมีเพื่อลงไปยังไดเรกทอรีอื่น
แต่ทุบตีสามารถทำได้:
$ shopt -s globstar
$ set -- "$dir"/**/*
$ for f; do printf '<%s>\n' "$f"; done
<deep/inside/a/dir/directory>
<deep/inside/a/dir/directory/file>
<deep/inside/a/dir/directory/file name>
<deep/inside/a/dir/directory/file with a
newline>
<deep/inside/a/dir/directory/zz last file>
<deep/inside/a/dir/file>
<deep/inside/a/dir/file name>
<deep/inside/a/dir/file with a
newline>
<deep/inside/a/dir/zz last file>
ในการเลือกไฟล์บางไฟล์เท่านั้น (เช่นไฟล์ที่ลงท้ายด้วยไฟล์) ให้แทนที่ *:
$ set -- "$dir"/**/*file
$ printf '<%s>\n' "$@"
<deep/inside/a/dir/directory/file>
<deep/inside/a/dir/directory/zz last file>
<deep/inside/a/dir/file>
<deep/inside/a/dir/zz last file>
แข็งแรง
เมื่อคุณวาง "พื้นที่ปลอดภัย " ในชื่อเรื่องฉันจะถือว่าสิ่งที่คุณหมายถึงคือ " แข็งแกร่ง "
วิธีที่ง่ายที่สุดในการเพิ่มความแข็งแกร่งให้กับช่องว่าง (หรือการขึ้นบรรทัดใหม่) คือการปฏิเสธการประมวลผลอินพุตที่มีช่องว่าง (หรือการขึ้นบรรทัดใหม่) วิธีที่ง่ายมากในการทำเช่นนี้ในเชลล์คือการออกโดยมีข้อผิดพลาดหากชื่อไฟล์ใด ๆ ขยายด้วยช่องว่าง มีหลายวิธีในการทำเช่นนี้ แต่คอมแพคที่สุด (และ posix) (แต่ จำกัด เฉพาะเนื้อหาไดเรกทอรีเดียวรวมถึงชื่อ suddirectories และหลีกเลี่ยงจุดไฟล์) คือ:
$ set -- "$dir"/file* # read the directory
$ a="$(printf '%s' "$@" x)" # make it a long string
$ [ "$a" = "${a%% *}" ] || echo "exit on space" # if $a has an space.
$ nl='
' # define a new line in the usual posix way.
$ [ "$a" = "${a%%"$nl"*}" ] || echo "exit on newline" # if $a has a newline.
หากโซลูชันที่ใช้มีความทนทานในรายการเหล่านี้ให้ลบการทดสอบ
ในทุบตีไดเรกทอรีย่อยสามารถทดสอบได้ทันทีพร้อมกับ ** อธิบายข้างต้น
มีสองวิธีในการรวมไฟล์ดอทโซลูชัน Posix คือ:
set -- "$dir"/* "$dir"/.[!.]* "$dir"/..?*
หา
หากการค้นหาต้องใช้ด้วยเหตุผลบางอย่างให้แทนที่ตัวคั่นด้วย NUL (0x00)
ทุบตี 4.4+
$ readarray -t -d '' arr < <(find "$dir" -type f -name file\* -print0)
$ printf '<%s>\n' "${arr[@]}"
<deep/inside/a/dir/file name>
<deep/inside/a/dir/file with a
newline>
<deep/inside/a/dir/directory/file name>
<deep/inside/a/dir/directory/file with a
newline>
<deep/inside/a/dir/directory/file>
<deep/inside/a/dir/file>
bash 2.05+
i=1 # lets start on 1 so it works also in zsh.
while IFS='' read -d '' val; do
arr[i++]="$val";
done < <(find "$dir" -type f -name \*file -print0)
printf '<%s>\n' "${arr[@]}"
POSIXLY
ในการสร้างโซลูชัน POSIX ที่ถูกต้องซึ่งการค้นหาไม่มีตัวคั่น NUL และไม่มี-d
(หรือ-a
) สำหรับการอ่านเราจำเป็นต้องมีโปรแกรม aproach entirelly ที่แตกต่างกัน
เราจำเป็นต้องใช้คอมเพล็กซ์-exec
จาก find ด้วยการเรียกไปยัง shell:
find "$dir" -type f -exec sh -c '
for f do
echo "<$f>"
done
' sh {} +
หรือหากสิ่งที่จำเป็นคือการเลือก (select เป็นส่วนหนึ่งของ bash ไม่ใช่ sh):
$ find "$dir" -type f -exec bash -c '
select f; do echo "<$f>"; break; done ' bash {} +
1) deep/inside/a/dir/file name
2) deep/inside/a/dir/zz last file
3) deep/inside/a/dir/file with a
newline
4) deep/inside/a/dir/directory/file name
5) deep/inside/a/dir/directory/zz last file
6) deep/inside/a/dir/directory/file with a
newline
7) deep/inside/a/dir/directory/file
8) deep/inside/a/dir/file
#? 3
<deep/inside/a/dir/file with a
newline>
[1]ต้นไม้นี้ (\ 012 เป็นบรรทัดใหม่):
$ tree
.
└── deep
└── inside
└── a
└── dir
├── directory
│ ├── file
│ ├── file name
│ └── file with a \012newline
├── file
├── file name
├── otherfile
├── with a\012newline
└── zz last file
สามารถสร้างได้ด้วยสองคำสั่งนี้:
$ mkdir -p deep/inside/a/dir/directory/
$ touch deep/inside/a/dir/{,directory/}{file{,\ {name,with\ a$'\n'newline}},zz\ last\ file}