1.
Yang pertama:
for f in *; do
echo "$f"
done
gagal untuk file yang dipanggil -n
, -e
dan varian menyukai -nene
dan 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 *
, find
tidak melakukan apa-apa selain mencetak file yang diterimanya sebagai argumen. Anda juga bisa menggunakan printf '%s\n'
yang seperti printf
yang 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)
bash
tidak 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 -print0
ekstensi non-standar GNU / BSD ).
Itu masih melibatkan pemunculan perintah find dan menggunakan while read
loop lambat , jadi itu mungkin akan lebih lambat daripada menggunakan for
loop kecuali daftar file sangat besar.
4.
Selain itu, bertentangan dengan ekspansi wildcard, find
akan melakukan lstat
panggilan sistem pada setiap file, jadi tidak mungkin bahwa non-sorting akan mengimbangi itu.
Dengan GNU / BSD find
, itu bisa dihindari dengan menggunakan -maxdepth
ekstensi mereka yang akan memicu optimasi menyimpan lstat
:
find . -maxdepth 1 ! -name '.*' -print0 |
while IFS= read -rd '' f; do
printf '%s\n' "$f"
done
Karena find
mulai 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 find
selesai menemukan semua file. Pada sistem GNU dan FreeBSD, Anda dapat menggunakannya stdbuf
untuk menyebabkan hal itu terjadi lebih cepat (menonaktifkan buffering stdio).
5.
Cara POSIX / standar / portabel untuk menjalankan perintah untuk setiap file find
adalah dengan menggunakan -exec
predikat:
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 echo
sementara find
perlu memunculkan proses baru dan mengeksekusi /bin/echo
di dalamnya untuk setiap file.
Jika Anda perlu menjalankan beberapa perintah, Anda dapat melakukan:
find . ! -name . -prune ! -name '.*' -exec cmd1 {} ';' -exec cmd2 {} ';'
Namun waspadalah yang cmd2
hanya dijalankan jika cmd1
berhasil.
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 echo
karena kami menggunakan versi bawaan sh
dan -exec +
versi memunculkan sesedikit sh
mungkin.
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, bash
jauh lebih lambat daripada kerang lain untuk itu).
find
tidak membuka file yang ditemukannya. Satu-satunya hal yang saya bisa lihat menggigit Anda di sini sehubungan dengan sejumlah besar file adalah ARG_MAX .