pengulangan awk {n} tidak berfungsi

18

Saya mencoba untuk mencetak garis menggunakan simbol pengulangan {n} tetapi tidak berfungsi. Untuk. misal saya ingin mencetak semua baris yang panjangnya 4 char

 awk '/^.{4}$/' test_data

Kode di atas tidak mencetak itu. Bagaimana memperbaikinya sehingga saya dapat menggunakan simbol pengulangan? Saya tahu alternatif suka awk '/^....$/' test_datadanawk 'length ==3 ' test_data

Pembelajar Selamanya
sumber
3
Distribusi apa yang Anda gunakan? Awk yang mana?
terdon
1
$ awk --versi GNU Awk 3.1.7 $ cat / etc / redhat-release Red Hat Enterprise Linux Server rilis 6.7 (Santiago)
Forever Learner
2
Saya akan mengatakan awk '/^.{4}+$/{print}' <<<$'foods\nbaarsz\nfooo' untuk mencocokkan tepat 4 karakter. Juga seperti yang Anda sebutkan, awk 'length($0) == 4' test_datakompatibel dengan hampir semua awkversi.
Valentin Bajrami
4
Lakukan awk --re-interval '/^.{4}$/' test_data atau awk --posix '/^.{4}$/' test_databekerja?
steeldriver
Steeldriver terima kasih. Ini menyelesaikan masalah saya. Terpilih. Terima kasih lagi :)
Forever Learner

Jawaban:

19

Menurut Panduan Pengguna Awk GNU: Riwayat Fitur , dukungan untuk operator rentang ekspresi reguler ditambahkan dalam versi 3.0 tetapi pada awalnya diperlukan opsi baris perintah eksplisit

Opsi baris perintah baru:

  • Opsi baris perintah baru:
    • Opsi --lint-old untuk memperingatkan tentang konstruk yang tidak tersedia dalam versi awk Versi 7 Unix awk (lihat V7 / SVR3.1).
    • Opsi -m dari BWK awk. (Brian masih di Bell Laboratories pada saat itu.) Ini kemudian dihapus dari kedua pekerjaannya dan dari penglihatan.
    • Opsi --re-interval untuk memberikan ekspresi interval dalam regexps (lihat Operator Regexp).
    • Opsi --traditional ditambahkan sebagai nama yang lebih baik untuk --compat (lihat Opsi).

Di gawk4.0,

Ekspresi interval menjadi bagian dari ekspresi reguler standar

Karena Anda menggunakan gawk3.x, Anda harus menggunakan

awk --re-interval '/^.{4}$/'

atau

awk --posix '/^.{4}$/'

atau (terima kasih @ StéphaneChazelas) jika Anda menginginkan solusi yang portabel, gunakan

POSIXLY_CORRECT=anything awk '/^.{4}$/'

(karena --posixatau --re-intervalakan menyebabkan kesalahan dalam awkimplementasi lain ).

Steeldriver
sumber
Terima kasih steeldriver, atas waktu dan bantuan Anda. Terpilih dan diterima sebagai jawaban
Forever Learner
4
Lebih baik digunakan POSIXLY_CORRECT=anything awk '/^.{4}/'karena membuat kode portabel ( --posixatau --re-intervalakan menyebabkan kesalahan dalam awkimplementasi lain ).
Stéphane Chazelas
Hai Stéphane Chazelas, ketika saya mengeluarkan perintah, $ POSIXLY_CORRECT = apapun awk '/^.{4}/' test_data, itu mencetak semua baris. Kemudian saya menyadari bahwa tidak ada dolar terakhir setelah pengulangan. Terima kasih atas masukan Anda. Memvotasikan komentar dan solusi Anda. Maaf saya salah paham karena penghapusan $ setelah pengulangan.
Forever Learner
20

EREs ( ekspresi reguler yang diperluas seperti yang digunakan oleh awkatau egrep) pada awalnya tidak dimiliki {x,y}. Ini pertama kali diperkenalkan di BREs (seperti yang digunakan oleh grepatau sed), tetapi dengan \{x,y\}sintaks yang tidak merusak portabilitas mundur.

Tetapi ketika itu ditambahkan ke EREs dengan {x,y}sintaks itu, itu benar-benar menghancurkan portabilitas karena foo{2}RE cocok dengan sesuatu yang berbeda sebelumnya.

Jadi beberapa implementasi memilih untuk tidak melakukannya. Anda akan menemukan itu /bin/awk, /bin/nawkdan /bin/egreppada Solaris masih tidak menghormatinya (Anda perlu menggunakan /usr/xpg4/bin/awkatau /usr/xpg4/bin/grep -E). Sama untuk awkdan nawkdi FreeBSD (berdasarkan pada yang awkdikelola oleh Brian Kernighan ( kdalam awk)).

Untuk GNUawk , hingga yang relatif baru (versi 4.0), Anda harus memanggilnya POSIXLY_CORRECT=anything awk '/^.{4}$/'untuk menghormatinya. mawkmasih tidak menghormatinya .

Perhatikan bahwa operator itu hanya gula sintaksis. .{3,5}dapat selalu ditulis ....?.?misalnya (meskipun tentu saja {3,5}jauh lebih terbaca, dan setara (foo.{5,9}bar){123,456}akan jauh lebih buruk).

Stéphane Chazelas
sumber
Terima kasih lagi Stéphane Chazelas. Maaf, salah saya, saya tidak dapat memahami jawaban Anda pada awalnya. Terima kasih banyak dan terunggah.
Forever Learner
6

Ini berfungsi seperti yang diharapkan dengan GNU awk(gawk):

$ printf 'abcd\nabc\nabcde\n' | gawk '/^.{4}$/'
abcd

Tetapi gagal dengan mawkyang lebih dekat dengan POSIX awkdan, AFAIK, adalah default pada sistem Ubuntu:

$ printf 'abcd\nabc\nabcde\n' | mawk '/^.{4}$/'
$ ## prints nothing

Jadi, solusi sederhana akan menggunakan gawkbukan awk. The {n}notasi bukan bagian dari sintaks POSIX BRE (ekspresi reguler dasar). Itu sebabnya grepjuga gagal di sini:

$ printf 'abcd\nabc\nabcde\n' | grep '^.{4}$'
$

Namun, itu adalah bagian dari ERE (ekspresi reguler yang diperluas):

$ printf 'abcd\nabc\nabcde\n' | grep -E '^.{4}$'
abcd

Saya tidak tahu rasa regex mana yang digunakan oleh mawkatau POSIX awk, tapi saya rasa itu BRE. Mereka menggunakan versi ERE yang lebih lama sesuai dengan jawaban Stéphane . Bagaimanapun, Anda tampaknya menggunakan versi awkyang tidak menerapkan ERE atau input Anda sebenarnya tidak memiliki garis dengan tepat 4 karakter. Ini bisa terjadi karena spasi putih yang tidak Anda lihat atau hapus kode mesin terbang, misalnya.

terdon
sumber
Hai terdon, saya ingin mencetak garis yang panjangnya 4 karakter. Bukan empat karakter pertama dalam satu baris. Misalnya $ grep -E '^. {4} $' test_data, akan berfungsi tetapi sama tidak bekerja dengan awk
Forever Learner
@ CppLearner ya, itulah yang saya lakukan di sini. Apa maksudmu?
terdon
@CppLearner, solusi @ terdon hanya mencetak garis yang panjangnya 4 karakter. Tetapi jika Anda benar-benar hanya tertarik pada panjang garis, Anda harus menggunakan length($0)yang lebih efisien daripada regex.
Stephen Kitt
Hai terdon, solusi steeldriver adalah apa yang saya cari. Terima kasih atas waktunya. Hai Stephen Kitt, Seperti yang saya sebutkan dalam masalah, saya sudah menggunakan panjang sebagai alternatif, saya lebih tertarik mengetahui mengapa regex pengulangan {n} tidak bekerja dari komentar steeldriver. Saya jadi tahu bahwa saya perlu menggunakan opsi untuk --re-interval atau --posix. Terima kasih atas waktunya.
Forever Learner
1
mawktidak terlalu dekat dengan POSIX awk, dan tidak menggunakan BRE. Itu memang menggunakan ERE tetapi tanpa {x,y}operator.
Stéphane Chazelas