Bagaimana saya bisa memahami ini atau itu (2 hal) dalam file?

38

Saya memiliki file yang memiliki "lalu" dan "di sana".

saya bisa

$ grep "then " x.x
x and then some
x and then some
x and then some
x and then some

dan saya bisa

$ grep "there " x.x
If there is no blob none some will be created

Bagaimana saya bisa mencari keduanya dalam satu operasi? Saya mencoba

$ grep (then|there) x.x

-bash: kesalahan sintaks dekat token yang tidak terduga `('

dan

grep "(then|there)" x.x
durrantm.../code
# (Nothing)
Michael Durrant
sumber

Jawaban:

54

Anda harus memasukkan ekspresi dalam tanda kutip. Kesalahan yang Anda terima adalah hasil dari bash mengartikan (sebagai karakter khusus.

Juga, Anda perlu memberi tahu grep untuk menggunakan ekspresi reguler yang diperluas.

$ grep -E '(then|there)' x.x

Tanpa ekspresi reguler diperpanjang, Anda harus melarikan diri |, (dan ). Perhatikan bahwa kami menggunakan tanda kutip tunggal di sini. Bash memperlakukan backslash dalam tanda kutip ganda khusus.

$ grep '\(then\|there\)' x.x

Pengelompokan tidak diperlukan dalam kasus ini.

$ grep 'then\|there' x.x

Ini akan diperlukan untuk sesuatu seperti ini:

$ grep 'the\(n\|re\)' x.x

sumber
3
Lihat juga grep $'then\nthere'dan grep -e then -e there. Perhatikan bahwa \|ini bukan standar dalam BRE. Sisanya adalah. Bash memperlakukan backslashes khusus dalam tanda kutip ganda hanya sebelum ", $, \ , `dan baris baru.
Stéphane Chazelas
1
Apa tujuannya x.x?
alex
7

Hanya tambahan cepat, sebagian besar rasa memiliki perintah yang disebut egrep yang hanya grep dengan -E. Saya pribadi suka mengetik yang lebih baik

egrep "i(Pod|Pad|Phone)" access.log

Daripada menggunakan grep -E

Trausti Thor
sumber
2

Hal-hal yang didokumentasikan dalam EKSPRESI REGULER di halaman manual (atau setidaknya, saya) sebenarnya untuk regexps yang diperluas ;

grep memahami tiga versi berbeda dari sintaks ekspresi reguler: “basic,” “extended” dan “perl.” Dalam GNU grep, tidak ada perbedaan dalam fungsionalitas yang tersedia antara sintaksis dasar dan extended. Dalam implementasi lain, ekspresi reguler dasar kurang kuat. Deskripsi berikut ini berlaku untuk ekspresi reguler yang diperluas; perbedaan untuk ekspresi reguler dasar dirangkum setelahnya.

Tetapi secara default grep tidak menggunakannya - Anda memerlukan -Esakelar:

grep "(then|there)" x.x

Karena (dari halaman manual lagi):

Dasar vs Ekspresi Reguler Diperpanjang

Dalam ekspresi reguler dasar, meta-karakter?, +, {, |, (, Dan) kehilangan makna khusus mereka; alih-alih gunakan versi backslashed \ ?, +, {, \ |, (, dan).

Jadi, Anda juga dapat menggunakan:

grep "then\|there" x.x

Karena tanda kurung berlebihan dalam kasus ini.

goldilocks
sumber
0

Kesederhanaan elegan Bash tampaknya hilang di halaman manualnya yang besar.

Selain solusi hebat di atas, saya pikir saya akan mencoba memberi Anda lembar contekan tentang bagaimana bash mem-parsing dan menginterpretasikan pernyataan . Kemudian dengan menggunakan peta jalan ini saya akan menguraikan contoh-contoh yang disajikan oleh penanya untuk membantu Anda lebih memahami mengapa mereka tidak berfungsi sebagaimana dimaksud.


Catatan: Baris skrip Shell digunakan secara langsung. Input-line yang diketik adalah histori pertama yang diperluas.

Setiap baris bash pertama-tama ditandai , atau dengan kata lain dipotong menjadi apa yang disebut token . (Tokenisasi terjadi sebelum semua ekspansi lainnya, termasuk penjepit, tilde, parameter, perintah, aritmatika, proses, pemisahan kata, & ekspansi nama file.)

Token di sini berarti bagian dari jalur input dipisahkan (dibatasi) oleh salah satu karakter meta khusus ini:

space,  - White space...
tab, 
newline,

‘<’,    - Redirection & piping...
‘|’, 
‘>’
‘&’,    - And/Both < | > | >>  .or.  &<file descriptor>

‘;’,    - Command termination

‘(’,    - Subshell, closed by -     ‘)’

Bash menggunakan banyak karakter khusus lainnya tetapi hanya 10 yang menghasilkan token awal.

Namun karena meta-karakter ini juga terkadang harus digunakan dalam token, perlu ada cara untuk menghilangkan makna khusus mereka. Ini disebut melarikan diri. Lolos dilakukan baik dengan mengutip string dari satu atau lebih karakter, (yaitu 'xx..', "xx.."), atau dengan mengawali karakter individu dengan garis miring, (yaitu \x). (Ini sedikit lebih rumit dari ini karena tanda kutip juga perlu dikutip, dan karena tanda kutip ganda tidak mengutip semuanya, tetapi penyederhanaan ini akan berlaku untuk saat ini.)

Jangan bingung mengutip bash dengan gagasan mengutip string teks, seperti dalam bahasa lain. Apa yang ada di antara tanda kutip di bash bukanlah string, melainkan bagian dari baris input yang memiliki meta-karakter yang lolos sehingga mereka tidak membatasi token.

Perhatikan, ada perbedaan penting antara ', dan ", tapi itu untuk hari lain.

Meta-karakter unescaped yang tersisa kemudian menjadi pemisah token.

Sebagai contoh,

$ echo "x"'y'\g
xyg

$ echo "<"'|'\>
<|>

$ echo x\; echo y
x; echo y

Dalam contoh pertama ada dua token yang dihasilkan oleh pembatas ruang: echodan xyz.

Demikian juga pada contoh ke-2.

Pada contoh ketiga titik koma adalah melarikan diri, jadi ada 4 token yang dihasilkan oleh pembatas ruang, echo, x;, echo, dan y. Token pertama kemudian dijalankan sebagai perintah, dan mengambil tiga token berikutnya sebagai input. Catatan 2 echotidak dieksekusi.


Yang penting untuk diingat adalah bahwa penampilan pertama bash untuk karakter melarikan diri ( ', ", dan \), dan kemudian mencari pembatas meta-karakter yang tidak lolos, dalam urutan itu.

Jika tidak lolos maka 10 karakter khusus ini berfungsi sebagai tokenpembatas. Beberapa dari mereka juga memiliki makna tambahan, tetapi pertama dan terutama, mereka adalah pembatas token.


Apa yang diharapkan grep

Dalam contoh di atas grep perlu token ini, grep, string, filename.

Percobaan pertama adalah:

$ grep (lalu | di sana) xx

Dalam hal ini (, )dan |adalah meta karakter unescaped dan berfungsi untuk membagi masukan ke token ini: grep, (, then, |, there, ), dan x.x. grep ingin melihat grep, then|theredan x.x.

Percobaan kedua adalah:

grep "(lalu | sana)" xx

Ini tokenizes ke grep, (then|there), x.x. Anda dapat melihat ini jika Anda menukar grep dengan gema:

echo "(lalu | di sana)" xx
(lalu | di sana) xx

Pandangan elips
sumber