GNU/Linux >> Belajar Linux >  >> Linux

Ulangi daftar file dengan spasi

Ada juga solusi yang sangat sederhana:andalkan bash globbing

$ mkdir test
$ cd test
$ touch "stupid file1"
$ touch "stupid file2"
$ touch "stupid   file 3"
$ ls
stupid   file 3  stupid file1     stupid file2
$ for file in *; do echo "file: '${file}'"; done
file: 'stupid   file 3'
file: 'stupid file1'
file: 'stupid file2'

Perhatikan bahwa saya tidak yakin perilaku ini adalah yang default tetapi saya tidak melihat pengaturan khusus di shopt saya jadi saya akan pergi dan mengatakan bahwa itu harus "aman" (diuji pada osx dan ubuntu).


Ada beberapa cara yang bisa diterapkan untuk mencapai hal ini.

Jika Anda ingin tetap menggunakan versi aslinya, ini dapat dilakukan dengan cara ini:

getlist() {
        IFS=$'\n'
        for file in $(find . -iname 'foo*') ; do
                printf 'File found: %s\n' "$file"
        done
}

Ini masih akan gagal jika nama file memiliki baris baru literal di dalamnya, tetapi spasi tidak akan merusaknya.

Namun, mengotak-atik IFS tidak perlu. Inilah cara pilihan saya untuk melakukan ini:

getlist() {
    while IFS= read -d $'\0' -r file ; do
            printf 'File found: %s\n' "$file"
    done < <(find . -iname 'foo*' -print0)
}

Jika Anda menemukan < <(command) sintaks asing Anda harus membaca tentang substitusi proses. Keuntungan dari for file in $(find ...) ini apakah file dengan spasi, baris baru, dan karakter lain ditangani dengan benar. Ini berfungsi karena find dengan -print0 akan menggunakan null (alias \0 ) sebagai terminator untuk setiap nama file dan, tidak seperti baris baru, null bukanlah karakter resmi dalam nama file.

Keuntungan dari ini dibandingkan versi yang hampir setara

getlist() {
        find . -iname 'foo*' -print0 | while read -d $'\0' -r file ; do
                printf 'File found: %s\n' "$file"
        done
}

Apakah itu penugasan variabel apa pun di badan while loop dipertahankan. Yaitu, jika Anda mem-pipe ke while seperti di atas maka badan dari while ada dalam subkulit yang mungkin bukan yang Anda inginkan.

Keuntungan dari versi substitusi proses dibandingkan find ... -print0 | xargs -0 minimal:xargs version baik-baik saja jika yang Anda butuhkan hanyalah mencetak satu baris atau melakukan satu operasi pada file, tetapi jika Anda perlu melakukan beberapa langkah, versi loop lebih mudah.

EDIT :Ini skrip pengujian yang bagus sehingga Anda bisa mendapatkan gambaran tentang perbedaan antara berbagai upaya untuk memecahkan masalah ini

#!/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"

Anda dapat mengganti perulangan berbasis kata dengan perulangan berbasis baris:

find . -iname "foo*" | while read f
do
    # ... loop body
done

Linux
  1. Cara Menemukan Semua File dengan Ukuran File Nol (0) Bytes di Direktori Secara Rekursif

  2. Menemukan file yang dapat dibaca manusia di unix

  3. Kecualikan daftar file dari find

  1. Temukan file dan direktori di Linux dengan perintah find

  2. Looping Melalui File Dengan Spasi Dalam Nama??

  3. Periksa penggunaan disk dari file yang dikembalikan dengan spasi

  1. Bagaimana saya bisa membuat daftar file dengan jalur absolutnya di Linux?

  2. Temukan file dan tar (dengan spasi)

  3. Buat daftar semua file gambar grafik dengan find?