1.
Yang pertama:
for f in *; do
echo "$f"
done
gagal untuk file yang dipanggil -n, -edan varian menyukai -nenedan dengan beberapa penyebaran bash, dengan nama file yang mengandung backslash.
Kedua:
find * -prune | while read f; do
echo "$f"
done
gagal untuk bahkan lebih kasus (file disebut !, -H, -name, (, nama file yang dimulai atau berakhir dengan kosong atau berisi karakter baris baru ...)
Shell yang mengembang *, findtidak melakukan apa-apa selain mencetak file yang diterimanya sebagai argumen. Anda juga bisa menggunakan printf '%s\n'yang seperti printfyang dibangun juga akan menghindari potensi kesalahan terlalu banyak args .
2.
Perluasan *diurutkan, Anda dapat membuatnya sedikit lebih cepat jika Anda tidak perlu menyortir. Di zsh:
for f (*(oN)) printf '%s\n' $f
atau hanya:
printf '%s\n' *(oN)
bashtidak memiliki setara sejauh yang saya tahu, jadi Anda harus menggunakan find.
3.
find . ! -name . -prune ! -name '.*' -print0 |
while IFS= read -rd '' f; do
printf '%s\n' "$f"
done
(di atas menggunakan -print0ekstensi non-standar GNU / BSD ).
Itu masih melibatkan pemunculan perintah find dan menggunakan while readloop lambat , jadi itu mungkin akan lebih lambat daripada menggunakan forloop kecuali daftar file sangat besar.
4.
Selain itu, bertentangan dengan ekspansi wildcard, findakan melakukan lstatpanggilan sistem pada setiap file, jadi tidak mungkin bahwa non-sorting akan mengimbangi itu.
Dengan GNU / BSD find, itu bisa dihindari dengan menggunakan -maxdepthekstensi mereka yang akan memicu optimasi menyimpan lstat:
find . -maxdepth 1 ! -name '.*' -print0 |
while IFS= read -rd '' f; do
printf '%s\n' "$f"
done
Karena findmulai mengeluarkan nama file segera setelah ditemukan (kecuali untuk buffer keluaran stdio), yang mungkin lebih cepat adalah jika apa yang Anda lakukan dalam loop memakan waktu dan daftar nama file lebih dari buffer stdio (4 / 8 kB). Dalam hal ini, pemrosesan dalam loop akan dimulai sebelum findselesai menemukan semua file. Pada sistem GNU dan FreeBSD, Anda dapat menggunakannya stdbufuntuk menyebabkan hal itu terjadi lebih cepat (menonaktifkan buffering stdio).
5.
Cara POSIX / standar / portabel untuk menjalankan perintah untuk setiap file findadalah dengan menggunakan -execpredikat:
find . ! -name . -prune ! -name '.*' -exec some-cmd {} ';'
Dalam hal ini echo, itu kurang efisien daripada melakukan perulangan di shell karena shell akan memiliki versi builtin echosementara findperlu memunculkan proses baru dan mengeksekusi /bin/echodi dalamnya untuk setiap file.
Jika Anda perlu menjalankan beberapa perintah, Anda dapat melakukan:
find . ! -name . -prune ! -name '.*' -exec cmd1 {} ';' -exec cmd2 {} ';'
Namun waspadalah yang cmd2hanya dijalankan jika cmd1berhasil.
6.
Cara kanonik untuk menjalankan perintah kompleks untuk setiap file adalah dengan memanggil shell dengan -exec ... {} +:
find . ! -name . -prune ! -name '.*' -exec sh -c '
for f do
cmd1 "$f"
cmd2 "$f"
done' sh {} +
Saat itu, kami kembali menjadi efisien echokarena kami menggunakan versi bawaan shdan -exec +versi memunculkan sesedikit shmungkin.
7.
Dalam pengujian saya pada direktori dengan 200.000 file dengan nama pendek di ext4, yang zsh(paragraf 2.) sejauh ini tercepat, diikuti oleh for i in *loop sederhana pertama (meskipun seperti biasa, bashjauh lebih lambat daripada kerang lain untuk itu).
findtidak membuka file yang ditemukannya. Satu-satunya hal yang saya bisa lihat menggigit Anda di sini sehubungan dengan sejumlah besar file adalah ARG_MAX .