Pertama-tama untuk memotong jawaban yang sepele tetapi tidak dapat diterapkan: Saya tidak dapat menggunakan trik find
+ xargs
variannya (seperti find
dengan -exec
) karena saya perlu menggunakan beberapa ekspresi seperti itu per panggilan. Saya akan kembali ke ini di akhir.
Sekarang untuk contoh yang lebih baik mari kita pertimbangkan:
$ find -L some/dir -name \*.abc | sort
some/dir/1.abc
some/dir/2.abc
some/dir/a space.abc
Bagaimana saya meneruskannya sebagai argumen program
?
Melakukannya saja tidak berhasil
$ ./program $(find -L some/dir -name \*.abc | sort)
gagal karena program
mendapat argumen berikut:
[0]: ./program
[1]: some/dir/1.abc
[2]: some/dir/2.abc
[3]: some/dir/a
[4]: space.abc
Seperti dapat dilihat, jalan dengan ruang terpecah dan program
menganggapnya sebagai dua argumen yang berbeda.
Kutip sampai berfungsi
Tampaknya pengguna pemula seperti saya, ketika dihadapkan dengan masalah seperti itu, cenderung secara acak menambahkan tanda kutip sampai akhirnya berfungsi - hanya di sini sepertinya tidak membantu ...
"$(…)"
$ ./program "$(find -L some/dir -name \*.abc | sort)"
[0]: ./program
[1]: some/dir/1.abc
some/dir/2.abc
some/dir/a space.abc
Karena tanda kutip mencegah pemisahan kata, semua file dilewatkan sebagai argumen tunggal.
Mengutip jalur individu
Pendekatan yang menjanjikan:
$ ./program $(find -L some/dir -name \*.abc -printf '"%p"\n' | sort)
[1]: "some/dir/1.abc"
[2]: "some/dir/2.abc"
[3]: "some/dir/a
[4]: space.abc"
Kutipan di sana, tentu. Tetapi mereka tidak lagi ditafsirkan. Mereka hanyalah bagian dari string. Jadi tidak hanya mereka tidak mencegah pemisahan kata, tetapi juga mereka bertengkar!
Ubah IFS
Lalu aku mencoba bermain-main dengan IFS
. Saya lebih suka find
dengan -print0
dan sort
dengan cara -z
apapun - sehingga mereka tidak akan memiliki masalah pada "jalur kabel" sendiri. Jadi mengapa tidak memaksakan pemisahan kata pada null
karakter dan memiliki semuanya?
$ ./program $(IFS=$'\0' find -L some/dir -name \*.abc -print0 | sort -z)
[0]: ./program
[1]: some/dir/1.abcsome/dir/2.abcsome/dir/a
[2]: space.abc
Jadi masih terbagi pada ruang dan tidak terpecah pada null
.
Saya mencoba untuk menempatkan IFS
tugas di $(…)
(seperti yang ditunjukkan di atas) dan sebelumnya ./program
. Juga saya mencoba sintaks lain seperti \0
, \x0
, \x00
baik dikutip dengan '
dan "
serta dengan dan tanpa $
. Tak satu pun dari mereka yang tampaknya membuat perbedaan ...
Dan di sini saya kehabisan ide. Saya mencoba beberapa hal lagi tetapi semua tampaknya berjalan ke masalah yang sama seperti yang tercantum.
Apa lagi yang bisa saya lakukan? Apakah bisa dilakukan?
Tentu, saya bisa program
menerima pola dan melakukan pencarian sendiri. Tapi itu banyak pekerjaan ganda sambil memperbaikinya ke sintaksis tertentu. (Bagaimana dengan menyediakan file dengan grep
contohnya?).
Saya juga bisa membuat program
menerima file dengan daftar jalur. Kemudian saya dapat dengan mudah membuang find
ekspresi ke beberapa file temp dan menyediakan path ke file itu saja. Ini dapat didukung berada di sepanjang jalur langsung sehingga jika pengguna hanya memiliki jalur sederhana itu dapat disediakan tanpa file perantara. Tapi ini sepertinya tidak bagus - orang perlu membuat file tambahan dan merawatnya, belum lagi implementasi tambahan yang diperlukan. (Di sisi positifnya, bagaimanapun, itu bisa menjadi penyelamatan untuk kasus-kasus di mana jumlah file sebagai argumen mulai menyebabkan masalah dengan panjang baris perintah ...)
Pada akhirnya, izinkan saya mengingatkan Anda lagi bahwa find
+ xargs
(dan sejenisnya) trik tidak akan berfungsi dalam kasus saya. Untuk kesederhanaan deskripsi, saya hanya menunjukkan satu argumen. Tetapi kasus saya yang sebenarnya lebih terlihat seperti ini:
$ ABC_FILES=$(find -L some/dir -name \*.abc | sort)
$ XYZ_FILES=$(find -L other/dir -name \*.xyz | sort)
$ ./program --abc-files $ABC_FILES --xyz-files $XYZ_FILES
Jadi melakukan xargs
dari satu pencarian masih membuat saya berurusan dengan yang lain ...
mapfile
(atau sinonimnyareadarray
). Tapi itu berhasil!