Pertanyaan `[!]` (tanda seru di dalam tanda kurung) wildcard dalam bash


Saya telah menemukan pola globbing dan wildcard dan minat khusus bagi saya adalah [!].

Konstruksi ini mirip dengan [!] membangun, kecuali daripada mencocokkan karakter apa pun di dalam tanda kurung, itu akan cocok dengan karakter apa pun, asalkan tidak tercantum di antara [ dan ].

rm myfile [!192]

Di atas, saya yakin akan menghapus setiap / semua file, kecuali untuk setiap / semua file yang memiliki 192 nama mereka.

Namun saya khawatir tentang penggunaan yang tepat dari ini dengan ekstensi file, dan khususnya beberapa kondisi.

Apa yang akan menjadi sintaks yang tepat dalam situasi seperti itu?

rm myfile [!.gif .csv. mp3] 

atau

rm myfile [!.gif !.csv !.mp3]

Kekhawatiran saya adalah bahwa periode tersebut mungkin salah tempat, dan sebagainya apa saja file dengan . (yang akan menjadi salah satu dari mereka pasti?) Kemudian akan dimanipulasi, ketika saya mencari untuk menyebabkan manipulasi file tertentu.

Konstruksi ini mirip dengan [ ] membangun, kecuali daripada mencocokkan karakter apa pun di dalam tanda kurung, itu akan cocok dengan karakter apa pun, asalkan tidak tercantum di antara [ dan ].

(dikutip dari http://www.tldp.org/LDP/GNU-Linux-Tools-Summary/html/x11655.htm)

Sekarang; bagi saya yang menyarankan kemudian tunggal ! sudah cukup, dan semua nilai yang ada di dalamnya terkandung dalam jangkauan.


10
2017-11-10 08:55


asal


sebagai tip umum, gunakan ls my-pattern atau echo my-command untuk memeriksa apakah goyangan dilakukan sesuai keinginan Anda, sebelum berlari rm - Wayne_Yux
Juga, ingat bahwa banyak, jika tidak sebagian besar, file tidak memiliki ekstensi. Ekstensi pada sistem Linux biasanya tidak relevan dan tidak digunakan untuk menentukan jenis file oleh sebagian besar program. - terdon♦
Perhatikan bahwa kutipan pertama Anda salah dikutip, sekarang tampaknya pada dasarnya mengatakan itu [!] mirip tetapi tidak seperti [!] - ilkkachu
Ini perlu disebutkan itu ^ memiliki arti yang sama persis dengan ! dalam konteks ini, oleh karena itu [^a] tidak termasuk a tepat seperti [!a] tidak: Jika karakter pertama mengikuti [is a! atau a ^ maka karakter apa pun yang tidak diapit akan dicocokkan. (man bash) - dessert
rm myfile [!192] akan dihapus myfile, serta file karakter tunggal apa pun yang tidak diberi nama 1, 9, atau 2. - Kevin


Jawaban:


Mengutip man 7 glob:

An  expression  "[!...]"  matches  a single character, namely any character
that is not matched by the expression obtained by removing the first '!' from it.
(Thus, "[!]a-]" matches any single character except ']', 'a' and '-'.)

Penekanan pada karakter tunggal bagian di sini, [] tidak dapat digunakan untuk seluruh string dalam Pencocokan Pola Bash.


bash's Ekspansi Brace dapat digunakan untuk mencocokkan string, namun tidak ada cara (saya tahu) untuk meniadakannya. Misalnya.

1.{gif,csv,mp3}

diperluas ke

1.gif 1.csv 1.mp3

tidak peduli apakah file-file ini ada.


Sebagai wchargin menunjukkan shopt dapat digunakan untuk mengaktifkan operator pencocokan pola tambahan, salah satunya !(). Setelah berlari shopt -s extglob, mis.

1.!(gif|csv|mp3)

diperluas ke

1.jpg 1.bmp 1.png

jika file-file itu ada di direktori saat ini. Untuk lebih banyak membaca man bash (bagian EXPANSION / Ekspansi Pathname) dan Ekspansi pathname (globbing).


Untuk apa yang Anda coba lakukan, saya selalu menggunakannya find, yang menawarkan negasi dan banyak lagi, mis. dengan cara berikut:

find . -maxdepth 1 -type f ! -name "*.gif" -a ! -name "*.csv" -a ! -name "*.mp3"

Ini hanya daftar temuan, jika Anda ingin menghapusnya, tambahkan saja -delete pilihan sampai akhir dari perintah. Seperti biasa dengan menghapus tindakan: Selalu periksa dengan hati-hati dulu.

find menawarkan banyak sekali opsi berguna yang dijelaskan dengan baik man find.


16
2017-11-10 09:11



Perhatikan bahwa ini find perintah bersifat rekursif (edit: seperti yang aslinya ditampilkan - Saya mungkin menyimpan komentar ini untuk informasi tambahan yang relevan tetapi tidak penting yang disampaikannya). Untuk menemukan file yang hanya berada di direktori saat ini tetapi tidak juga subdirektorinya - dan dengan demikian hanya menghapus file-file jika -delete tindakan ditambahkan - Anda dapat menambahkan -maxdepth 1 segera setelah find .. Ini akan membawanya sejalan dengan efek globbing, karena globs tidak bersifat rekursif di Bash kecuali globstar opsi shell dihidupkan dan ** digunakan. Gumpalan yang diperlihatkan dalam pertanyaan ini tidak bersifat rekursif di semua cangkang. - Eliah Kagan
"Tidak ada cara (saya tahu) untuk meniadakan mereka" —dengan shopt -s extglob, Kamu dapat memakai echo 1.!(gif|csv|mp3), yang mencetak semua 1.ext dimana ext tidak gif, csv, atau mp3. (Lihat "Pencocokan Pola" dari man bash.) - wchargin


Saya pikir Anda salah memahami penggunaan tanda kurung. [abc] cocok satu dari karakter a, b atau c. [!abc] cocok satu karakter itu tidak  a, b atau c. Jadi komandannya

rm myfile [192]

akan dihapus myfile dan file-file 1, 9 dan 2 karena Anda memiliki ruang antara myfile dan braket. Sebaliknya, perintahnya

rm myfile[192]

akan menghapus file myfile1, myfile9 dan myfile2.


10
2017-11-10 09:07



benar. Lebih baik digunakan find. - RoVo
Sebenarnya [] digunakan untuk rentang, [!] Satu karakter - IronUhlan
@IronUhlan, keduanya mengambil rentang atau daftar karakter. Hanya saja yang lain adalah negasi. - ilkkachu


Tanda kurung [  ] menunjukkan kelas karakter. Setiap karakter tunggal di dalamnya dapat cocok dengan posisi yang diberikan. Begitu

file[192]

cocok dengan tiga nama yang mungkin:

file1
file2
file9

Itu benar tidak pertandingan file192, karena hanya berurusan dengan satu karakter setelahnya file.

Kami juga dapat menggunakan rentang dalam tanda kurung. [0-9] cocok dengan satu digit di posisi yang diberikan. Untuk dua digit, kita perlu [0-9][0-9]. Untuk digit diikuti dengan huruf kapital, kita bisa menggunakannya [0-9][A-Z]...

! menunjukkan negasi.

file[!192]

akan mencocokkan file yang memiliki karakter tunggal setelahnya file kecuali 1 atau 9 atau 2. Misalnya akan cocok file7 dan files dan file% (dan banyak lainnya) tetapi tidak  file192, karena itu memiliki dua karakter tambahan.

Untuk kasus penggunaan Anda, saya sarankan untuk menggunakan find dari pada [!]. Ia memiliki a not operator.

Itu juga rekursif, yang berarti masuk ke semua subdirektori secara default. Anda dapat membatasi ke direktori saat ini dengan -maxdepth 1, jika itu yang kamu inginkan. Shell wildcard (globbing) adalah non-rekursif (meskipun globing rekursif dengan ** dapat diaktifkan).

Dengan asumsi Anda tidak ingin menghindari menghapus symlink, kita dapat menambahkan -type d ke tes yang dinegasikan untuk menghindari penghapusan direktori apa pun. Terima kasih kepada Eliah Kagan untuk saran itu.

find /path -maxdepth 1 -not \( -type d -or -iname "*.gif" -or -iname "*.csv" -or -iname "*.mp3" \)

Jika Anda melihat apa yang Anda inginkan, Anda dapat menjalankan perintah lagi dengan -delete

find /path -maxdepth 1  -not \( -type d -or -iname "*.gif" -or -iname "*.csv" -or -iname "*.mp3" \) -delete

7
2017-11-10 09:16



Dan saya pikir Anda juga dapat melakukan beberapa rentang sekaligus. Misalnya, digit heksadesimal bisa [0-9a-fA-F] - Wilson
@Zanna, ya! Saya benar-benar menggunakan temuan :) Tidak menyadari itu memiliki operator "tidak" :) - IronUhlan