Apa perbedaan antara `a [bc] d` (kurung) dan` a {b, c} d` (kurung kurawal)?

28

Apa perbedaan antara a[bc]ddan a{b,c}d? Mengapa orang menggunakan a{b,c}dketika sudah ada a[bc]d?

Weijun Zhou
sumber
Siapa yang menyuruhmu menggunakannya command a[bc]d?
Jesse_b
3
Ini tentu memiliki kegunaannya jika orang memahaminya dengan benar.
Weijun Zhou
7
Saya kira saya tidak mengerti bagaimana kebingungan antara keduanya terjadi.
Jesse_b
Saya telah secara eksplisit diminta oleh rekan kerja yang kurang akrab dengan Linux dalam hal ini, meskipun tidak baru-baru ini.
Weijun Zhou
@ Jesse_b Jika Anda hanya pernah mencobanya dengan operasi pada file suka lsdan Anda hanya pernah mencoba karakter tunggal, mereka akan tampak bekerja sama.
Nacht - Pasang kembali Monica

Jawaban:

43

Keduanya sangat berbeda.

a[bc]dadalah pola nama file (dalam cangkang selain fish). Ini akan diperluas ke dua nama file abd dan acdjika itu adalah nama file yang ada di direktori saat ini.

  • Bagian [...]ini adalah ekspresi kurung yang cocok dengan satu karakter dari yang tercantum (atau menyusun elemen ketika rentang disertakan). Untuk mencocokkan pola a[bc]d, karakter antara string adan dnama file harus berupa a batau a c.

  • Jika abdada, tetapi acdtidak, maka itu hanya akan berkembang menjadi abd, dan sebaliknya.

  • Jika tidak abd, atau acdada, tergantung pada shell dan pilihan, itu akan memicu kesalahan (asli Unix sh, (t)csh, zsh, fish, bash -O failglob) dan mungkin keluar dari shell, atau meninggalkan unexpanded¹ pola (Bourne-seperti dan rc-seperti kerang) atau memperluas ke tidak ada ( bash/zsh/yash -o nullglob, beberapa versi lama fish, Unix asli shdan (t)cshjika ada gumpalan lain yang cocok dalam perintah yang sama).

a{b,c}dadalah ekspansi brace (di shell yang mendukung ini). Ini akan berkembang ke dua string abd dan acd.

  • Bagian tersebut {...}adalah serangkaian string yang dibatasi koma (dalam contoh ini; dalam beberapa shell, itu juga dapat berupa rentang seperti a..katau 20..25atau yang lebih maju seperti 00..20..2atau 0..20..2%02d), dan ekspansi dihitung dengan menggabungkan masing-masing string ini dengan sisi-sisi. string adan d. String ini bisa lebih panjang dari satu karakter dan juga bisa menjadi penjepit ekspansi sendiri.

  • Ekspansi terjadi terlepas dari apakah string ini sesuai dengan nama file yang ada atau tidak.

Jika Anda membuat string, gunakan ekspansi brace. Jika Anda mencocokkan nama file, gunakan pola nama file.


¹ Dalam kasus khusus ini, a[bc]dbisa jadi itu adalah nama dari file yang sudah ada yang karenanya berpotensi berbahaya untuk menggunakan hal-hal seperti rm -f ./*.[ch]di shell itu dan rm -f ./*.{c,h}tidak terlalu menjadi masalah.

Kusalananda
sumber
Terima kasih telah menjelaskan "Jika abd ada, tetapi ACD tidak, maka itu hanya akan meluas ke abd". Saya kira itulah yang hilang dari jawaban saya.
Weijun Zhou
9
Perbedaan penting lainnya adalah bahwa di a{b,c}d, bagian bdan ctidak perlu menjadi huruf tunggal; mis ex{ten,ci}sion. Sementara ex[tenci]sionatau apa pun hanya akan cocok dengan salah satu dari surat-surat ini.
alexis
7

a[bc]dadalah pencocokan pola , dan merupakan bagian dari standar POSIX. Dalam POSIX, ini diperkenalkan sebagai "ekspresi braket pola". Itu didokumentasikan dalam bagian 2.13 manual

Ketika tidak dikutip dan di luar ekspresi braket, tiga karakter berikut harus memiliki arti khusus dalam spesifikasi pola:

    ?
      Tanda tanya adalah pola yang cocok dengan karakter apa pun.
    *
      Tanda bintang adalah pola yang harus cocok dengan banyak karakter, seperti dijelaskan dalam Pola yang Cocok dengan Banyak Karakter.
    [
      Braket terbuka harus memperkenalkan ekspresi braket pola.

Bagian 2.13.3 juga menyebutkan sesuatu yang berperilaku berbeda dari apa yang diharapkan seseorang untuk regex biasa ketika digunakan untuk ekspansi nama file (penekanan oleh saya)

Aturan yang dijelaskan sejauh ini dalam Pola Pencocokan Karakter Tunggal dan Pencocokan Pola Beberapa Karakter dikualifikasikan oleh aturan berikut yang berlaku ketika notasi pencocokan pola digunakan untuk ekspansi nama file:

Karakter garis miring dalam pathname harus dicocokkan secara eksplisit dengan menggunakan satu atau lebih garis miring dalam pola; itu tidak akan dicocokkan dengan asterisk atau karakter khusus tanda tanya atau dengan ekspresi tanda kurung. Garis miring pada pola harus diidentifikasi sebelum ekspresi braket; dengan demikian, garis miring tidak dapat dimasukkan dalam ekspresi braket pola yang digunakan untuk ekspansi nama file. Jika karakter garis miring ditemukan mengikuti karakter braket kotak terbuka yang tidak dihilangkan sebelum braket kotak penutupan yang sesuai ditemukan, braket terbuka harus diperlakukan sebagai karakter biasa. Misalnya, polanya "a[b/c]d"tidak cocok dengan nama path seperti abdatau a/d. Ini hanya cocok dengan nama path secara harfiah a[b/c]d.

a{b,c}dadalah perluasan kawat gigi , tidak dalam spesifikasi oleh POSIX. Inilah bagian yang sesuai dari manual bash (penekanan oleh saya):

Perluasan Brace adalah mekanisme dimana string sewenang-wenang dapat dihasilkan. Mekanisme ini mirip dengan ekspansi nama file (lihat Ekspansi Nama File), tetapi nama file yang dihasilkan tidak perlu ada . Pola yang akan diperluas diperluas dalam bentuk pembukaan opsional , diikuti oleh serangkaian string yang dipisahkan koma atau ekspresi urutan antara sepasang kawat gigi, diikuti oleh postscript opsional . Pembukaan diawali dengan setiap string yang terkandung dalam kurung kurawal, dan naskah tambahan kemudian ditambahkan ke setiap string yang dihasilkan, meluas dari kiri ke kanan.

Menurut komentar oleh @mosvy, ini pertama kali muncul dari cshtetapi perilaku di bashberbeda dari cshdan kerang lainnya. Jenis ekspansi kawat gigi juga hadir di glob(3).

Ada jenis lain dari ekspansi kawat gigi {a..z}yang hanya muncul setelah bash3.0, dan ada lebih banyak ditambahkan di bash4.0.

Dalam shell di mana globbing dihidupkan, jalankan di folder kosong, hasil berikut dikembalikan

$ echo a[bc]d
a[bc]d
$ echo a{b,c}d
abd acd

Menanggapi komentar @ Jesse_b, jika Anda berada di shell interaktif dan keduanya berlaku, a[bc]dlebih sedikit kesulitan mengetik. Sebagai contoh grep pattern [ab][12].txt.

Weijun Zhou
sumber
2
Ekspansi penjepit bukan "bashism"; pertama kali muncul csh, jauh sebelumnya bash. Ini juga hadir dalam fungsi perpustakaan glob (3). Perbedaannya adalah bahwa bashhal itu dilakukan sebelum ekspansi lain: a=A; ab=A/B; ac=A/C; echo $a{b,c}akan bekerja di bash berbeda dari shell lain.
Mosvy
Terima kasih. Saya akan memperbarui jawabannya.
Weijun Zhou