Saya ingin menggunakan find
untuk menemukan file dalam satu set folder yang dibatasi oleh wildcard, tetapi di mana ada spasi dalam nama path.
Dari baris perintah, ini mudah. Contoh-contoh berikut semuanya berfungsi.
find te*/my\ files/more -print
find te*/'my files'/more -print
find te*/my' 'files/more -print
Ini akan menemukan file di, misalnya, terminal/my files/more
dan tepid/my files/more
.
Namun, saya ingin ini menjadi bagian dari naskah; yang saya butuhkan adalah sesuatu seperti ini:
SEARCH='te*/my\ files/more'
find ${SEARCH} -print
Sayangnya, apa pun yang saya lakukan, saya tampaknya tidak dapat mencampur wildcard dan spasi dalam find
perintah dalam skrip. Contoh di atas mengembalikan kesalahan berikut (perhatikan penggandaan backslash yang tidak terduga):
find: ‘te*/my\\’: No such file or directory
find: ‘files/more’: No such file or directory
Mencoba menggunakan tanda kutip juga gagal.
SEARCH="te*/'my files'/more"
find ${SEARCH} -print
Ini mengembalikan kesalahan berikut, setelah mengabaikan arti dari kutipan:
find: ‘te*/'my’: No such file or directory
find: ‘files'/more’: No such file or directory
Ini satu contoh lagi.
SEARCH='te*/my files/more'
find ${SEARCH} -print
Seperti yang diharapkan:
find: ‘te*/my’: No such file or directory
find: ‘files/more’: No such file or directory
Setiap variasi yang saya coba mengembalikan kesalahan.
Saya memiliki solusi, yang berpotensi berbahaya karena mengembalikan terlalu banyak folder. Saya mengonversi semua spasi menjadi tanda tanya (wildcard satu karakter) seperti ini:
SEARCH='te*/my files/more'
SEARCH=${SEARCH// /?} # Convert every space to a question mark.
find ${SEARCH} -print
Ini setara dengan:
find te*/my?files/more -print
Ini mengembalikan tidak hanya folder yang benar tetapi juga terse/myxfiles/more
, yang seharusnya tidak.
Bagaimana saya bisa mencapai apa yang saya coba lakukan? Google belum membantu saya :(
SEARCH: command not found
perintahfind -print
yang dieksekusi.find "${SEARCH}" -print
?te*/'my files'/more
.Jawaban:
Perintah yang sama persis harus bekerja dengan baik dalam sebuah skrip:
Jika Anda perlu memilikinya sebagai variabel, itu akan menjadi sedikit lebih kompleks:
PERINGATAN:
Menggunakan
eval
seperti itu tidak aman dan dapat mengakibatkan mengeksekusi kode yang sewenang-wenang dan mungkin berbahaya jika nama file Anda dapat berisi karakter tertentu. Lihat bash FAQ 48 untuk detailnya.Lebih baik melewati jalan sebagai argumen:
Pendekatan lain adalah untuk menghindari
find
sama sekali dan menggunakan fitur globing dan bash global yang diperluas:The
globstar
pilihan pesta memungkinkan Anda menggunakan**
untuk mencocokkan rekursif:Untuk membuatnya bertindak 100% suka menemukan dan memasukkan file dot (file tersembunyi), gunakan
Anda dapat meratakannya
echo
secara langsung tanpa loop:sumber
Bagaimana dengan array?
(*)
memperluas ke array apa pun yang cocok dengan wildcard. Dan"${SEARCH[@]}"
mengembang ke semua elemen dalam array ([@]
), dengan masing-masing dikutip secara individual.Terlambat, saya menyadari bahwa dirinya harus mampu melakukan ini. Sesuatu seperti:
sumber
INPUTPATH='te*/my files/more
danSEARCH=(${INPUTPATH})
. Tidak peduli bagaimana saya memvariasikan cara saya melakukan ini, saya tetap berakhir dengan hasil yang tidak fungsional. Ini sepertinya tidak mungkin!find
's-path
filter? Ini menggunakan wildcard dan jelas tidak perlu ekspansi.-path
. Namun, dalam 10 menit terakhir, saya telah menemukan jawabannya: gunakaneval
! Tampaknya lebih sederhana daripada-path
.Saya akhirnya menemukan jawabannya.
Tambahkan garis miring terbalik ke semua spasi:
Pada titik ini,
SEARCH
berisite*/my\ files/more
.Lalu, gunakan
eval
.Sesederhana itu! Menggunakan
eval
memotong interpretasi yang${SEARCH}
berasal dari variabel.sumber