Apa yang dilakukan `. []. Foo []` di bash? Mengapa cocok dengan `..`?

16

Lihatlah yang berikut ini:

$ echo .[].aliases[]
..
$ echo .[].foo[]
..
$ echo .[].[]
..
$ echo .[].xyz[]
..
$ echo .xyz[].xyz[]
.xyz[].xyz[]
$ echo .xyz[].[]
.xyz[].[]

Tampaknya ini sepertinya menggumpal sesuatu, tapi saya tidak mengerti bagaimana hasilnya menyatu. Dari pemahaman saya []adalah kelas karakter kosong. Akan intuitif jika

  • hanya cocok dengan string kosong; dalam hal ini, saya berharap bash untuk mereproduksi secara keseluruhan karena tidak ada yang cocok dengan itu di direktori ini, tetapi juga cocok dengan hal-hal seperti ..aliases(dalam contoh pertama),
  • atau tidak sama sekali; dalam hal ini, saya berharap bash akan mereproduksi string secara total juga.

Ini dengan GNU bash, versi 4.4.23 (1) -release.

Jonas Schäfer
sumber

Jawaban:

25

The [dimulai set. Satu set diakhiri oleh ]. Tetapi ada cara untuk memiliki ]sebagai bagian dari set, dan itu adalah untuk menentukan ]sebagai karakter pertama. Karena set kosong tidak masuk akal, ini tidak ambigu.

Jadi contoh Anda pada dasarnya semua titik diikuti oleh satu set yang berisi titik, karena itu cocok dengan dua titik.

Contoh-contoh selanjutnya tidak menemukan file apa pun dan karenanya dikembalikan kata demi kata.

RalfFriedl
sumber
4

Hanya string yang dikutip tidak dikenakan globbing:

$ echo ".[].aliases[]"
.[].aliases[]

Tetapi string yang tidak dikutip dapat mengalami globbing. String yang tidak dikutip yang berisi *atau ?atau (valid) [](ekspresi kurung) akan dimodifikasi oleh daftar file yang cocok dengannya. Dengan cara yang sama seperti *akan berubah menjadi semua file dalam direktori yang cocok dan ?akan mencocokkan file hanya dengan satu karakter, a (valid) []akan mencocokkan file dengan karakter di dalam tanda kurung. Titik adalah karakter yang valid:

$ echo a[.]b
a[.]b

$ touch "a.b"
$ echo a[.]b
a.b

Untuk dapat mencocokkannya, ]itu harus menjadi karakter pertama di dalam tanda kurung:

$ touch "a]b"
$ ls a[]]b
a]b

Ekspresi braket kosong tidak masuk akal (dan tidak diperluas):

$ touch ab
$ ls a[]b
ls: cannot access 'a[]b': No such file or directory

Itu sebabnya ini bekerja:

$ touch a]c abc afc azc a:c a?c aoc 
$ ls a[]bfz:?]c
abc  a:c  a?c  a]c  afc  azc

Untuk [idenya mirip:

$ touch a[c
$ ls a[[]c
a[c

tetapi bisa pada posisi apa pun dalam ekspresi braket:

$ ls a[]bf[z:?]c
abc  a:c  a?c  a[c  a]c  afc  azc

$ ls a[]bfz:?[]c
abc  a:c  a?c  a[c  a]c  afc  azc

String yang Anda posting .[].foo[]akan cocok dengan titik yang diikuti oleh a ], a ., a f, a oatau a [. Ini mirip dengan:

$ echo a[].foo[]c
a[c a]c afc aoc

Dan itu akan cocok sebagai berikut:

$ touch .] .f .o .[ .a .b .z

$ echo .[].foo[]
.. .[ .] .f .o

Perhatikan bahwa entri direktori ..tidak perlu dibuat karena ada di dalam setiap direktori secara default. Tetapi titik sederhana .tidak akan dicocokkan dengan bola karena perlu dicocokkan secara eksplisit (dengan benar-benar menggunakan titik).

Tapi itu tidak akan cocok ..aliaseskarena ekspresi braket hanya akan cocok dengan satu karakter. Untuk mencocokkan beberapa karakter, Anda perlu menggunakan *(apa saja):

$ touch ..a ..l ..i ..aliases ..alias ..ali
$ echo .[].aliases[]
.. .[ .] .a

$ echo .[].aliases[]*
.. .[ .] .a ..a ..ali ..alias ..aliases ..i ..l
Ishak
sumber