la ripetizione di awk {n} non funziona


18

Sto cercando di stampare le linee usando il simbolo di ripetizione {n} ma non funziona. Per. ad es. voglio stampare tutte le linee la cui lunghezza è di 4 caratteri

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

Il codice sopra riportato non lo stampa. Come correggerlo in modo da poter utilizzare il simbolo di ripetizione? Conosco l'alternativa come awk '/^....$/' test_dataeawk 'length ==3 ' test_data


3
Quale distribuzione stai usando? Quale awk?
terdon

1
$ awk - versione GNU Awk 3.1.7 $ cat / etc / redhat-release Red Hat Enterprise Linux Server versione 6.7 (Santiago)
Forever Learner

2
Direi awk '/^.{4}+$/{print}' <<<$'foods\nbaarsz\nfooo' di abbinare esattamente 4 caratteri. Inoltre, come hai detto tu stesso, awk 'length($0) == 4' test_dataè compatibile con quasi tutte le awkversioni.
Valentin Bajrami,

4
Fare awk --re-interval '/^.{4}$/' test_data o awk --posix '/^.{4}$/' test_datalavorare?
steeldriver

Grazie steeldriver. Questo ha risolto il mio problema. Upvoted. Grazie ancora :)
Forever Learner

Risposte:


19

Secondo il Manuale dell'utente di GNU Awk: Cronologia delle funzionalità , il supporto per operatori di intervalli di espressioni regolari è stato aggiunto nella versione 3.0 ma inizialmente era richiesta l'opzione esplicita da riga di comando

Nuove opzioni della riga di comando:

  • Nuove opzioni della riga di comando:
    • L'opzione --lint-old per mettere in guardia su costrutti che non sono disponibili nella versione originale Unix di awk versione 7 (vedi V7 / SVR3.1).
    • L'opzione -m di BWK awk. (Brian era ancora ai Bell Laboratories in quel momento.) In seguito fu rimosso sia dal suo awk che da gawk.
    • L'opzione --re-intervallo per fornire espressioni di intervallo in regexps (consultare Operatori Regexp).
    • L'opzione --traditional è stata aggiunta come nome migliore per --compat (vedi Opzioni).

In gawk4.0,

Le espressioni a intervalli sono diventate parte delle espressioni regolari predefinite

Dato che stai usando gawk3.x, dovrai usarlo

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

o

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

o (grazie @ StéphaneChazelas) se vuoi una soluzione portatile, usa

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

(poiché --posixo --re-intervalcauserebbe un errore in altre awkimplementazioni).


Grazie steeldriver, per il tuo tempo e aiuto. Votato e accettato come risposta
Forever Learner

4
È meglio usare in POSIXLY_CORRECT=anything awk '/^.{4}/'quanto rende il codice portatile (un --posixo --re-intervalcauserebbe un errore in altre awkimplementazioni).
Stéphane Chazelas,

Ciao Stéphane Chazelas, quando ho dato il comando $ POSIXLY_CORRECT = qualcosa di diverso '/^.{4}/' test_data, ha stampato tutte le righe. Poi ho capito che non c'è l'ultimo dollaro dopo le ripetizioni. Grazie per i tuoi input. Aggiornamento del commento e della soluzione. Mi dispiace di averlo frainteso in primo luogo a causa dell'omissione della $ dopo la ripetizione.
Forever Learner

20

Inizialmente gli ERE ( espressioni regolari estese come utilizzate da awko egrep) inizialmente non avevano {x,y}. È stato introdotto per la prima volta in BRE (come usato da grepo sed), ma con la \{x,y\}sintassi che non ha rotto la portabilità all'indietro.

Ma quando è stato aggiunto agli ERE con quella {x,y}sintassi, ha rotto la portabilità all'indietro poiché un foo{2}RE corrispondeva a qualcosa di diverso prima.

Quindi alcune implementazioni hanno scelto di non farlo. Troverete che /bin/awk, /bin/nawke /bin/egrepsu Solaris ancora non onorate (è necessario utilizzare /usr/xpg4/bin/awko /usr/xpg4/bin/grep -E). Lo stesso vale per awke nawksu FreeBSD (in base alla awkmantenuto da Brian Kernighan (la ka awk)).

Per GNUawk , fino a tempi relativamente recenti (versione 4.0), dovevi chiamarlo POSIXLY_CORRECT=anything awk '/^.{4}$/'per renderlo onore. mawknon lo onora ancora .

Si noti che quell'operatore è solo zucchero sintattico. .{3,5}può sempre essere scritto ....?.?per esempio (anche se ovviamente {3,5}è molto più leggibile e l'equivalente di (foo.{5,9}bar){123,456}sarebbe molto peggio).


Grazie ancora Stéphane Chazelas. Mi dispiace, mio ​​male, inizialmente non sono riuscito a comprendere la tua risposta. Grazie mille e votato.
Forever Learner

6

Funziona come previsto con GNU awk(gawk):

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

Ma non riesce con il mawkquale è più vicino a POSIX awke, AFAIK, è l'impostazione predefinita sui sistemi Ubuntu:

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

Quindi, al gawkposto di utilizzare una soluzione semplice awk. La {n}notazione non fa parte della sintassi POSIX BRE (espressione regolare di base). Ecco perché grepanche qui fallisce:

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

Tuttavia, fa parte di ERE (espressioni regolari estese):

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

Non so quale sapore regex è usato da mawko POSIX awk, ma immagino che sia BRE. Usano una versione precedente di ERE secondo la risposta di Stéphane . In ogni caso, o apparentemente stai usando una versione awkche non implementa ERE o il tuo input in realtà non ha righe con esattamente 4 caratteri. Questo potrebbe accadere a causa di spazi bianchi che non vedi o Unicode glifi, ad esempio.


Ciao terdon, voglio stampare le righe che sono lunghe 4 caratteri. Non i primi quattro caratteri di una riga. Ad esempio $ grep -E '^. {4} $' test_data, funzionerà ma lo stesso non funziona con awk
Forever Learner

@CppLearner sì, è quello che sto facendo qui. Cosa intendi?
terdon

@CppLearner, la soluzione di @ terdon stampa solo righe lunghe 4 caratteri. Ma se sei davvero interessato solo alla lunghezza della linea, dovresti semplicemente usare length($0)quale è più efficiente delle regex.
Stephen Kitt,

Ciao terdon, la soluzione di Steeldriver è quello che stavo cercando. Grazie per il tuo tempo. Ciao Stephen Kitt, Come ho già detto nel problema, ho già usato la lunghezza come alternativa, ero più interessato a sapere perché la regex di ripetizione {n} non funziona dal commento di Steeldriver, sono venuto a sapere che ho bisogno di usare l'opzione di --re-intervallo o --posix. Grazie per il tuo tempo.
Forever Learner

1
mawknon è molto più vicino a POSIX awke non usa BRE. Utilizza ERE ma senza l' {x,y}operatore.
Stéphane Chazelas,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.