Mengapa echo {1,2,3}diperluas ke 1 2 3 yang merupakan perilaku yang diharapkan, sementara echo [[:digit:]]kembali [[:digit:]]sementara saya berharap untuk mencetak semua digit dari 0hingga 9?
Karena mereka adalah dua hal yang berbeda. Ini {1,2,3}adalah contoh dari ekspansi brace . The {1,2,3}membangun diperluas oleh shell , sebelum echobahkan melihatnya. Anda dapat melihat apa yang terjadi jika Anda menggunakan set -x:
$ set-x
$ echo {1,2,3}+ echo 123123
Seperti yang Anda lihat, perintah echo {1,2,3}diperluas ke:
echo 123
Namun, [[:digit:]]adalah kelas karakter POSIX . Saat Anda memberikannya echo, shell juga memprosesnya terlebih dahulu, tapi kali ini ia diproses sebagai shell glob . ini bekerja dengan cara yang sama seperti jika Anda menjalankan echo *yang akan mencetak semua file di direktori saat ini. Tetapi [[:digit:]]apakah shell glob yang cocok dengan digit apa pun. Sekarang, dalam bash, jika shell glob tidak cocok dengan apa pun, itu akan diperluas ke dirinya sendiri:
Dalam kedua kasus, echohanya mencetak apa saja yang diperintahkan shell untuk dicetak, tetapi dalam kasus kedua, karena gumpalan cocok dengan sesuatu ( /etc) ia diminta untuk mencetak sesuatu itu.
Jadi, karena Anda tidak memiliki file atau direktori yang namanya persis terdiri dari satu digit (yang [[:digit:]]cocok dengan yang mana), gumpalan diperluas ke dirinya sendiri dan Anda mendapatkan:
$ echo [[:digit:]][[:digit:]]
Sekarang, coba buat file yang dipanggil 5dan jalankan perintah yang sama:
$ echo [[:digit:]]5
Dan jika ada lebih dari satu file yang cocok:
$ touch 15
$ echo [[:digit:]]15
Ini (semacam) didokumentasikan dalam man bashpenjelasan nullglobopsi yang mematikan perilaku ini:
nullglob
Ifset, bash allows patterns which match no files (see
PathnameExpansion above) to expand to a null string,
rather than themselves.
Lihat juga shopt -s failglobuntuk mendapatkan perilaku yang lebih bermanfaat mirip dengan kerang modern seperti zshatau fish.
Stéphane Chazelas
Saya setuju dengan Stéphane, gunakan failglob. nullglobdapat menyebabkan masalah yang tidak terduga, misalnya saat menempelkan URL yang kebetulan memiliki ?.
Kevin
1
Tentu, saya hanya menyebutkan nullglobuntuk menunjukkan bahwa polanya ditafsirkan sebagai gumpalan oleh shell.
terdon
14
{1,2,3}adalah brace ekspansi , itu memperluas ke kata-kata yang tercantum tanpa memperhatikan artinya.
[...]adalah grup karakter, digunakan dalam ekspansi nama file (atau wildcard, atau glob) mirip dengan tanda bintang *dan tanda tanya ?. Ini cocok dengan setiap karakter yang terdaftar di dalam, atau karakter yang merupakan anggota dari kelompok yang disebutkan seperti [:digit:]jika mereka terdaftar. Perilaku default kebanyakan shell adalah membiarkan wildcard apa adanya jika tidak ada file yang cocok dengannya.
(Perhatikan bahwa Anda tidak dapat benar-benar mengubah wildcard / pola menjadi rangkaian string yang cocok dengan itu. Tanda bintang dapat mencocokkan string apa pun dengan panjang apa pun, jadi jika memperluas pola apa pun yang berisinya akan menghasilkan daftar string yang tak terbatas.)
Begitu:
$ bash -c 'echo [[:digit:]]'# bash leaves it as-is[[:digit:]]
$ zsh -c 'echo [[:digit:]]'# zsh by default complains if no match
zsh:1: no matches found:[[:digit:]]
$ touch 13 d i g t
$ bash -c 'echo [[:digit:]]'# now there are two matches13# note that d, i, g and t do NOT match
Tetapi tetap saja:
$ bash -c 'echo {1,2,3}'123
Keduanya diperluas oleh shell , tidak masalah jika perintah yang Anda jalankan adalah ls, atau echoatau rm. Juga perhatikan bahwa jika salah satu dari mereka dikutip, mereka tidak akan diperluas:
$ bash -c 'echo "[[:digit:]]"'# even though matching files still exist[[:digit:]]
$ bash -c 'echo "{1,2,3}"'{1,2,3}
terima kasih atas jawaban Anda, saya baru di linux jadi izinkan saya bertanya kepada Anda bagaimana gema terkait dengan file 1 3, fungsinya adalah untuk mencetak argumennya untuk stdout tidak mencari file seperti pengetahuan saya
AbdAllah Talaat
1
@AbdAllahTalaat ini tidak ada hubungannya dengan gema, sebenarnya. Shell (misalnya bash) akan "memperluas" [[:digit:]]sebelum melewatinya echo, jadi echotidak pernah melihat [[:digit:]], ia hanya melihat 1 3. Anda dapat melihat ini dalam tindakan dengan menjalankan set -xyang akan mencetak perintah yang sebenarnya sedang dijalankan (jalankan set +xuntuk mematikannya lagi).
terdon
@AbdAllahTalaat, echotidak mencari file, shell tidak, sebelum menjalankan echo.
ilkkachu
Terutama karena saya pikir dalam DOS / Windows utilitas memperluas wildcard, bukan shell. (Saya mungkin salah)
ilkkachu
maaf kawan, saya menggeser jawaban yang benar ke jawaban tedron karena komentarnya mengandung arti bahwa bash adalah apa yang tidak dikerjakan oleh pekerjaan ... jawabannya juga mengandung makna itu .. kalian semua membantu saya ... saya berharap jika saya bisa meletakkan jawaban yang benar untuk semua jawaban dan komentar Anda
AbdAllah Talaat
4
{1,2,3}(dan misalnya {1..3}adalah penjepit ekspansi . Mereka ditafsirkan oleh shell sebelum eksekusi perintah.
[[:digit:]]adalah token pencocokan pola , tetapi Anda tidak menggunakannya di lokasi dengan file apa pun yang cocok dengan pola itu. Jika Anda menggunakan kecocokan pola yang tidak memiliki kecocokan, itu berkembang dengan sendirinya:
Jawaban:
Karena mereka adalah dua hal yang berbeda. Ini
{1,2,3}
adalah contoh dari ekspansi brace . The{1,2,3}
membangun diperluas oleh shell , sebelumecho
bahkan melihatnya. Anda dapat melihat apa yang terjadi jika Anda menggunakanset -x
:Seperti yang Anda lihat, perintah
echo {1,2,3}
diperluas ke:Namun,
[[:digit:]]
adalah kelas karakter POSIX . Saat Anda memberikannyaecho
, shell juga memprosesnya terlebih dahulu, tapi kali ini ia diproses sebagai shell glob . ini bekerja dengan cara yang sama seperti jika Anda menjalankanecho *
yang akan mencetak semua file di direktori saat ini. Tetapi[[:digit:]]
apakah shell glob yang cocok dengan digit apa pun. Sekarang, dalam bash, jika shell glob tidak cocok dengan apa pun, itu akan diperluas ke dirinya sendiri:Jika glob cocok dengan sesuatu, itu akan dicetak:
Dalam kedua kasus,
echo
hanya mencetak apa saja yang diperintahkan shell untuk dicetak, tetapi dalam kasus kedua, karena gumpalan cocok dengan sesuatu (/etc
) ia diminta untuk mencetak sesuatu itu.Jadi, karena Anda tidak memiliki file atau direktori yang namanya persis terdiri dari satu digit (yang
[[:digit:]]
cocok dengan yang mana), gumpalan diperluas ke dirinya sendiri dan Anda mendapatkan:Sekarang, coba buat file yang dipanggil
5
dan jalankan perintah yang sama:Dan jika ada lebih dari satu file yang cocok:
Ini (semacam) didokumentasikan dalam
man bash
penjelasannullglob
opsi yang mematikan perilaku ini:Jika Anda mengatur opsi ini:
sumber
shopt -s failglob
untuk mendapatkan perilaku yang lebih bermanfaat mirip dengan kerang modern sepertizsh
ataufish
.failglob
.nullglob
dapat menyebabkan masalah yang tidak terduga, misalnya saat menempelkan URL yang kebetulan memiliki?
.nullglob
untuk menunjukkan bahwa polanya ditafsirkan sebagai gumpalan oleh shell.{1,2,3}
adalah brace ekspansi , itu memperluas ke kata-kata yang tercantum tanpa memperhatikan artinya.[...]
adalah grup karakter, digunakan dalam ekspansi nama file (atau wildcard, atau glob) mirip dengan tanda bintang*
dan tanda tanya?
. Ini cocok dengan setiap karakter yang terdaftar di dalam, atau karakter yang merupakan anggota dari kelompok yang disebutkan seperti[:digit:]
jika mereka terdaftar. Perilaku default kebanyakan shell adalah membiarkan wildcard apa adanya jika tidak ada file yang cocok dengannya.(Perhatikan bahwa Anda tidak dapat benar-benar mengubah wildcard / pola menjadi rangkaian string yang cocok dengan itu. Tanda bintang dapat mencocokkan string apa pun dengan panjang apa pun, jadi jika memperluas pola apa pun yang berisinya akan menghasilkan daftar string yang tak terbatas.)
Begitu:
Tetapi tetap saja:
Keduanya diperluas oleh shell , tidak masalah jika perintah yang Anda jalankan adalah
ls
, atauecho
ataurm
. Juga perhatikan bahwa jika salah satu dari mereka dikutip, mereka tidak akan diperluas:sumber
[[:digit:]]
sebelum melewatinyaecho
, jadiecho
tidak pernah melihat[[:digit:]]
, ia hanya melihat1 3
. Anda dapat melihat ini dalam tindakan dengan menjalankanset -x
yang akan mencetak perintah yang sebenarnya sedang dijalankan (jalankanset +x
untuk mematikannya lagi).echo
tidak mencari file, shell tidak, sebelum menjalankanecho
.{1,2,3}
(dan misalnya{1..3}
adalah penjepit ekspansi . Mereka ditafsirkan oleh shell sebelum eksekusi perintah.[[:digit:]]
adalah token pencocokan pola , tetapi Anda tidak menggunakannya di lokasi dengan file apa pun yang cocok dengan pola itu. Jika Anda menggunakan kecocokan pola yang tidak memiliki kecocokan, itu berkembang dengan sendirinya:sumber