SORU
12 AĞUSTOS 2011, Cuma


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
12 AĞUSTOS 2011, Cuma


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"

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Christopher Bill

    Christopher

    30 NİSAN 2009
  • ShotgunSandwichENT

    ShotgunSandw

    3 EKİM 2012
  • The Fashion Sight

    The Fashion

    22 AĞUSTOS 2011