Saya berulang kali memiliki masalah ini: Saya memiliki bola, yang cocok persis dengan file yang benar, tetapi menyebabkan Command line too long
. Setiap kali saya mengubahnya menjadi beberapa kombinasi find
dan grep
yang berfungsi untuk situasi tertentu, tetapi yang tidak 100% setara.
Sebagai contoh:
./foo*bar/quux[A-Z]{.bak,}/pic[0-9][0-9][0-9][0-9]?.jpg
Apakah ada alat untuk mengubah gumpalan menjadi find
ekspresi yang tidak saya sadari? Atau apakah ada opsi untuk find
mencocokkan gumpalan tanpa mencocokkan gumpalan yang sama dalam subdir (misalnya foo/*.jpg
tidak diizinkan untuk mencocokkan bar/foo/*.jpg
)?
-path
atau-ipath
.find . -path './foo*bar/quux[A-Z]/pic[0-9][0-9][0-9][0-9]?.jpg'
harus bekerja - kecuali itu akan cocok/fooz/blah/bar/quuxA/pic1234d.jpg
. Apakah itu akan menjadi masalah?echo <glob> | cat
, dengan asumsi pengetahuan saya tentang bash, gema adalah built-in, dan dengan demikian tidak memiliki batas perintah maksJawaban:
Jika masalahnya adalah Anda mendapatkan kesalahan argumen-list-is-too-long, gunakan loop, atau shell built-in. Meskipun
command glob-that-matches-too-much
bisa error,for f in glob-that-matches-too-much
tidak, jadi Anda bisa melakukan:Perulangan mungkin sangat lambat, tetapi seharusnya berhasil.
Atau:
(
printf
dibangun di sebagian besar shell, cara di atas bekerja di sekitar batasanexecve()
panggilan sistem)Juga bekerja dengan bash. Saya tidak yakin persis di mana ini didokumentasikan.
Baik Vim
glob2regpat()
dan Pythonfnmatch.translate()
dapat mengonversi gumpalan ke regex, tetapi keduanya juga digunakan.*
untuk*
, cocok di seluruh/
.sumber
something
dengan yangecho
seharusnya melakukannya.printf
- itu akan lebih cepat daripada meneleponecho
ribuan kali, dan menawarkan lebih banyak fleksibilitas.exec
, yang berlaku untuk perintah eksternal seperticat
; tetapi batas itu tidak berlaku untuk perintah builtin shell sepertiprintf
.printf
merupakan builtin, dan shell mungkin menggunakan metode yang sama untuk memasok argumen padanya yang mereka gunakan untuk menghitung argumenfor
.cat
bukan builtin.mksh
manaprintf
tidak builtin dan kerang seperti diksh93
manacat
(atau bisa) builtin. Lihat jugazargs
dizsh
untuk bekerja di sekitarnya tanpa harus resor untukxargs
.find
(untuk-name
/-path
predikat standar) menggunakan pola wildcard seperti gumpalan (perhatikan bahwa{a,b}
bukan operator gumpal; setelah ekspansi, Anda mendapatkan dua gumpalan). Perbedaan utama adalah penanganan garis miring (dan file titik dan direktori tidak diperlakukan secara khususfind
).*
dalam gumpalan tidak akan menjangkau beberapa direktori.*/*/*
akan menyebabkan hingga 2 level direktori terdaftar. Menambahkan-path './*/*/*'
akan cocok dengan semua file yang memiliki setidaknya 3 level dan tidak akan berhentifind
dari daftar isi direktori apa pun pada kedalaman apa pun.Untuk itu
beberapa gumpalan, mudah untuk menerjemahkan, Anda menginginkan direktori pada kedalaman 3, sehingga Anda dapat menggunakan:
(atau
-depth 3
dengan beberapafind
implementasi). Atau POSIXly:Yang akan menjamin itu
*
dan?
tidak bisa cocok dengan/
karakter.(
find
, bertentangan dengan gumpalan akan membaca isi direktori selain darifoo*bar
yang ada di direktori saat ini¹, dan tidak mengurutkan daftar file. Tetapi jika kita mengesampingkan masalah apa yang cocok dengan[A-Z]
atau perilaku*
/?
berkaitan dengan karakter yang tidak valid adalah tidak ditentukan, Anda akan mendapatkan daftar file yang sama).Tetapi bagaimanapun juga, seperti yang telah ditunjukkan oleh @muru , tidak perlu menggunakan
find
jika hanya untuk membagi daftar file menjadi beberapa proses untuk mengatasi batasexecve()
panggilan sistem. Beberapa kerang sepertizsh
(denganzargs
) atauksh93
(dengancommand -x
) bahkan memiliki dukungan bawaan untuk itu.Dengan
zsh
(yang gumpalannya juga setara dengan-type f
dan sebagian besarfind
predikat lainnya ), misalnya:(Apakah
(|.bak)
operator glob bertentangan dengan{,.bak}
,(.)
kualifikasi glob adalah setarafind
dengan-type f
, tambahkanoN
di sana untuk melewati pengurutan seperti denganfind
,D
untuk memasukkan file dot (tidak berlaku untuk glob ini))¹ Agar
find
dapat merayapi pohon direktori seperti yang akan terjadi, Anda memerlukan sesuatu seperti:Itu memangkas semua direktori pada level 1 kecuali
foo*bar
yang, dan semua pada level 2 kecualiquux[A-Z]
atauquux[A-Z].bak
yang, lalu pilihpic...
yang di level 3 (dan memangkas semua direktori di level itu).sumber
Anda dapat menulis regex untuk menemukan yang cocok dengan kebutuhan Anda:
sumber
.
, tambahkan pertandingan opsional untuk.bak
dan perubahan*
untuk[^/]*
tidak cocok jalur seperti / foo / foo / bar dll[0-9][0-9][0-9][0-9]?
menjadi[0-9]{3,4}
Generalisasi pada catatan pada jawaban saya yang lain , sebagai jawaban yang lebih langsung untuk pertanyaan Anda, Anda dapat menggunakan
sh
skrip POSIX ini untuk mengubah bola menjadifind
ekspresi:Untuk digunakan dengan satu
sh
gumpalan standar (jadi bukan dua gumpalan contoh Anda yang menggunakan ekspansi brace ):(itu tidak mengabaikan file dot atau dot-dir kecuali
.
dan..
dan tidak mengurutkan daftar file).Yang itu hanya bekerja dengan gumpalan relatif ke direktori saat ini, tanpa
.
atau..
komponen. Dengan sedikit usaha, Anda dapat memperluasnya ke gumpalan mana pun, lebih dari satu gumpalan ... Itu juga dapat dioptimalkan sehinggaglob2find 'dir/*'
tidak terlihatdir
sama seperti halnya sebuah pola.sumber