GNU/Linux >> Belajar Linux >  >> Linux

Mengapa Looping Over Find's Output Praktik Buruk?

Pertanyaan ini terinspirasi oleh

Mengapa menggunakan loop shell untuk memproses teks dianggap sebagai praktik yang buruk?

Saya melihat konstruksi ini

for file in `find . -type f -name ...`; do smth with ${file}; done

dan

for dir in $(find . -type d -name ...); do smth with ${dir}; done

digunakan di sini hampir setiap hari bahkan jika beberapa orang meluangkan waktu untuk mengomentari posting tersebut menjelaskan mengapa hal semacam ini harus dihindari…
Melihat jumlah posting tersebut (dan fakta bahwa kadang-kadang komentar tersebut hanya diabaikan) Saya pikir sebaiknya saya mengajukan pertanyaan:

Mengapa mengulang find praktik buruk keluaran dan apa cara yang tepat untuk menjalankan satu atau lebih perintah untuk setiap nama file/jalur yang dikembalikan oleh find ?

Jawaban yang Diterima:

Masalahnya

for f in $(find .)

menggabungkan dua hal yang tidak kompatibel.

find mencetak daftar jalur file yang dibatasi oleh karakter baris baru. Sementara operator split+glob yang dipanggil saat Anda meninggalkan $(find .) tidak dikutip dalam konteks daftar itu membaginya pada karakter $IFS (secara default termasuk baris baru, tetapi juga spasi dan tab (dan NUL di zsh )) dan melakukan globbing pada setiap kata yang dihasilkan (kecuali dalam zsh ) (dan bahkan menahan ekspansi dalam turunan ksh93 atau pdksh!).

Bahkan jika Anda berhasil:

IFS='
' # split on newline only
set -o noglob # disable glob (also disables brace expansion in pdksh
              # but not ksh93)
for f in $(find .) # invoke split+glob

Itu masih salah karena karakter baris baru sama validnya dengan apa pun di jalur file. Output dari find -print sama sekali tidak dapat diandalkan pasca-proses (kecuali dengan menggunakan beberapa trik yang berbelit-belit, seperti yang ditunjukkan di sini ).

Itu juga berarti shell perlu menyimpan output dari find sepenuhnya, lalu split+glob (yang berarti menyimpan output itu untuk kedua kalinya dalam memori) sebelum mulai mengulang file.

Perhatikan bahwa find . | xargs cmd memiliki masalah yang sama (ada, kosong, baris baru, kutipan tunggal, kutipan ganda dan garis miring terbalik (dan dengan beberapa xarg byte implementasi yang tidak membentuk bagian dari karakter yang valid) adalah masalah)

Alternatif yang lebih tepat

Satu-satunya cara untuk menggunakan for loop pada output find akan menggunakan zsh yang mendukung IFS=$'

Linux
  1. Mengapa Tidak 'menemukan' Tampilkan File Ini??

  2. Ssh – Mengapa Firefox Sangat Lambat Dibanding Ssh?

  3. Mengapa Opsi Ssh -t Menambahkan Cr &Lf Dalam Output yang Dialihkan?

  1. Batasi Cari Keluaran Dan Hindari Sinyal 13?

  2. Mengulangi setiap baris keluaran ls -l

  3. Mengapa pipa shell ini keluar?

  1. Mengapa Find Tidak Menerima '-exec Cp {} Dir +'?

  2. Mengapa Grep -o -w Tidak Memberi Saya Output yang Diharapkan Pada Mac Os X?

  3. Mengapa Ada Output Ping Setelah Dihentikan?