Bash : boşluk içeren dosya listesi üzerinde yineleme
Dosyaların listesini yinelemek istiyorum. Bu liste find
Bir komut sonucudur, ben ile geldi:
getlist() {
for f in $(find . -iname "foo*")
do
echo "File found: $f"
# do something useful
done
}
Eğer bir dosya adı boşluk varsa dışında sorun yok:
$ ls
foo_bar_baz.txt
foo bar baz.txt
$ getlist
File found: foo_bar_baz.txt
File found: foo
File found: bar
File found: baz.txt
Nasıl boşluk bölme önlemek için ne yapabilirim ?
CEVAP
Bunu yapmak için birkaç uygulanabilir yollar vardır.
Eğer yakından orijinal sürümü sopa istiyorsan bu şekilde yapılabilir:
getlist() {
IFS=$'\n'
for file in $(find . -iname 'foo*') ; do
printf 'File found: %s\n' "$file"
done
}
Bu hala dosya adları değişmez karakterlerine varsa başarısız olur, ama boşluk kırmayacak.
Ancak, EĞERLER ile uğraşmaya gerek yok. İşte bunu yapmak için tercih edilen yol:
getlist() {
while IFS= read -d $'\0' -r file ; do
printf 'File found: %s\n' "$file"
done < <(find . -iname 'foo*' -print0)
}
Eğer < <(command)
sözdizimi yabancı bulursanız process substitution hakkında okumalısınız. for file in $(find ...)
bu avantajı boşluk, yeni satır ve diğer karakterler ile dosya doğru işlenir. Bu çalışır çünkü find
-print0
kullanım null
(aka \0
) olarak sonlandırıcı için her dosya, farklı olarak yeni satır boş değil yasal bir karakter bir dosya.
Neredeyse eşdeğer bir sürümü üzerinde bu avantajı
getlist() {
find . -iname 'foo*' -print0 | while read -d $'\0' -r file ; do
printf 'File found: %s\n' "$file"
done
}
Döngü korunmuş olsa bu vücutta herhangi bir değişken atama. Daha sonra while
vücut istediğiniz ne olabilir bir kabuk gibi yukarıda while
boru eğer.
Avantajı süreci ikame sürümü find ... -print0 | xargs -0
minimum: xargs
sürümü istiyorsan ihtiyacın olan şey yazdırmak için bir çizgi ya da gerçekleştirmek bir tek operasyonu dosyasını, ama eğer sen yapmak için birçok adım döngü sürümü daha kolay.
EDİTBurada bu sorunu çözmede farklı girişimleri arasındaki fark hakkında bir fikir edinebilirsiniz çok güzel bir test komut dosyası
#!/usr/bin/env bash
dir=/tmp/getlist.test/
mkdir -p "$dir"
cd "$dir"
touch 'file not starting foo' foo foobar barfoo 'foo with spaces'\
'foo with'$'\n'newline 'foo with trailing whitespace '
# while with process substitution, null terminated, empty IFS
getlist0() {
while IFS= read -d $'\0' -r file ; do
printf 'File found: '"'%s'"'\n' "$file"
done < <(find . -iname 'foo*' -print0)
}
# while with process substitution, null terminated, default IFS
getlist1() {
while read -d $'\0' -r file ; do
printf 'File found: '"'%s'"'\n' "$file"
done < <(find . -iname 'foo*' -print0)
}
# pipe to while, newline terminated
getlist2() {
find . -iname 'foo*' | while read -r file ; do
printf 'File found: '"'%s'"'\n' "$file"
done
}
# pipe to while, null terminated
getlist3() {
find . -iname 'foo*' -print0 | while read -d $'\0' -r file ; do
printf 'File found: '"'%s'"'\n' "$file"
done
}
# for loop over subshell results, newline terminated, default IFS
getlist4() {
for file in "$(find . -iname 'foo*')" ; do
printf 'File found: '"'%s'"'\n' "$file"
done
}
# for loop over subshell results, newline terminated, newline IFS
getlist5() {
IFS=$'\n'
for file in $(find . -iname 'foo*') ; do
printf 'File found: '"'%s'"'\n' "$file"
done
}
# see how they run
for n in {0..5} ; do
printf '\n\ngetlist%d:\n' $n
eval getlist$n
done
rm -rf "$dir"
Bulma tüm Linux üzerinde bir metin diz...
Nasıl bash sayı değişkenleri tarafında...
Nasıl bash script değişkenler üzerinde...
Nasıl dosyayı bir hex dökümü sadece he...
Tüm Dosya üzerinde Komut Çalıştırmak i...