Utilizzando il segno zodiacale in grep


90

Sto cercando di cercare la sottostringa "abc" in un file specifico in linux / bash

Faccio così:

grep '*abc*' myFile

Non restituisce nulla.

Ma se lo faccio:

grep 'abc' myFile

Restituisce le corrispondenze correttamente.

Ora, questo non è un problema per me. Ma cosa succede se voglio grep per una stringa più complessa, diciamo

*abc * def *

Come lo realizzerei usando grep?


3
grep stesso non supporta i caratteri jolly sulla maggior parte delle piattaforme. Devi usare egrep per usare i caratteri jolly. Le shell hanno una sintassi diversa. "*" nella shell è <qualsiasi stringa>. In egrep è un operatore che dice "0 a molte delle entità precedenti". In grep, è solo un personaggio normale.
PanCrit

@PanCrit: *significa la stessa cosa in grep ed egrep: è un quantificatore che significa zero o più dell'atomo precedente. Questo è un concetto completamente diverso dai caratteri jolly usati dalla shell.
Alan Moore

Risposte:


124

L'asterisco è solo un file operatore di ripetizione , ma devi dirgli cosa ripeti. /*abc*/corrisponde a una stringa contenente ab e zero o più c (perché il secondo * è sulla c; il primo è privo di significato perché non c'è nulla da ripetere). Se vuoi abbinare qualcosa, devi dire .*: il punto significa qualsiasi carattere ( entro determinate linee guida ). Se vuoi abbinare solo abc, potresti semplicemente dire grep 'abc' myFile. Per la tua corrispondenza più complessa, devi usare .*- grep 'abc.*def' myFileabbinerà una stringa che contiene abc seguito da def con qualcosa in mezzo.

Aggiornamento in base a un commento:

*in un'espressione regolare non è esattamente lo stesso di * nella console. Nella console, * fa parte di un costrutto glob e funge semplicemente da carattere jolly (ad esempio ls *.logelencherà tutti i file che terminano con .log). Tuttavia, nelle espressioni regolari, * è un modificatore, il che significa che si applica solo al carattere o al gruppo che lo precede. Se si desidera che * nelle espressioni regolari agisca come un carattere jolly, è necessario utilizzare .*come accennato in precedenza: il punto è un carattere jolly e la stella, quando si modifica il punto, significa trovare uno o più punti; cioè. trova uno o più caratteri.


1
Penso che l'interrogante sia confuso sulla differenza tra i caratteri jolly della shell e le espressioni regolari. Sospetto anche che l'espressione più complicata sarebbe: grep 'abc. * Def' (almeno uno spazio presente - forse due come ho scritto).
Jonathan Leffler

1
In realtà, l'interrogante sembra non capire che 'abc' non è la stessa cosa di '^ abc $' MrGreen
Massa

1
Sì, ero confuso tra glob e le espressioni regolari complete. Uso * senza punto per indicare la corrispondenza di qualsiasi cosa sulla shell.
Saobi

1
grep *significa "0 o più" e grep è avido per impostazione predefinita. Si noti che in grep fondamentali espressioni regolari i metacaratteri ?, +, {, |, (, e )perdono il loro significato speciale. Altre informazioni: grep
regexps

25

Il punto carattere significa corrispondenza con qualsiasi carattere, quindi .*significa zero o più occorrenze di qualsiasi carattere. Probabilmente intendi usare .*piuttosto che solo *.


Il punto è un meta carattere che accetta qualsiasi carattere tranne le nuove linee .
Abhishek Kamal

12

Il "segno zodiacale" ha significato solo se c'è qualcosa di fronte ad esso. Se lo strumento non è presente (grep in questo caso) potrebbe trattarlo come un errore. Per esempio:

'*xyz'    is meaningless
'a*xyz'   means zero or more occurrences of 'a' followed by xyz

5
* Non è privo di significato; semplicemente non ha il suo solito significato (di ripetizione) ma significa "sono una star". Corrisponderebbe a una riga contenente una stella seguita da x, yez.
Jonathan Leffler

2
@ Jonathan Dipende dallo strumento.

9

Usa grep -P - che abilita il supporto per le espressioni regolari in stile Perl.

grep -P "abc.*def" myfile

6

L'espressione che hai provato, come quelle che funzionano sulla riga di comando della shell in Linux, ad esempio, è chiamata " glob ". Le espressioni glob non sono espressioni regolari complete , che è ciò che grep usa per specificare le stringhe da cercare. Ecco un (vecchio, piccolo) post sulle differenze. Le espressioni glob (come in "ls *") vengono interpretate dalla shell stessa.

È possibile tradurre da glob a RE, ma in genere è necessario farlo nella tua testa.


1
È solo un glob se viene analizzato dalla shell. Dal momento che sta preservando la stringa di ricerca all'interno di virgolette singole, la shell lascia la stringa da sola e la passa intatta in argv a grep.
Conspicuous Compiler

4

Non stai usando espressioni regolari, quindi la tua variante grep di scelta dovrebbe essere fgrep, che si comporterà come ti aspetti.


2
fgrepè ora deprecato, grep -fdovrebbe essere usato invece.
Prometeo

1
Quello è "grep -F". Il buon vecchio fgrep potrebbe essere "deprecato", ma non lo porteranno via finché sarò ancora vivo.
Andrew Beals


1

Questa potrebbe essere la risposta che stai cercando:

grep abc MyFile | grep def

L'unica cosa è che ... emetterà righe dove "def" è prima OR dopo "abc"


1

Questo ha funzionato per me:

grep ". * $ {expr}" - con virgolette doppie, preceduto dal punto. Dove "expr" è qualsiasi stringa di cui hai bisogno alla fine della riga.

Grep standard unix senza interruttori aggiuntivi.


0

"*" funziona come un modificatore per l'elemento precedente. Quindi "abc * def" cerca "ab" seguito da 0 o più "c" seguite da "def".

Quello che probabilmente vuoi è "abc. * Def" che cerca "abc" seguito da un numero qualsiasi di caratteri, seguito da "def".

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.