2009-04-27 16 views
5

Mi sto perdendo completamente nella programmazione della shell, principalmente perché ogni sito che utilizzo offre diversi strumenti per eseguire la corrispondenza dei modelli. Quindi la mia domanda è quale strumento usare per fare la semplice corrispondenza dei pattern nel flusso di pipe.testo corrispondente tra virgolette (newbie)

contesto: Ho il file named.conf e ho bisogno di tutti i nomi delle zone in un file semplice per un'ulteriore elaborazione. Quindi faccio ~ $ cat named.local | zona di grep e completamente perso qui. Il mio output è di circa centoventi righe di nuova riga "zone" domain.tld "{" e ho bisogno di testo tra virgolette.

Grazie per aver mostrato un modo per farlo.

J

risposta

23

Penso che quello che stai cercando è sed ... è una s tream ndr itor che vi consente di fare sostituzioni con il metodo integrale.

Come stai spiegando, il comando `cat named.local | Zona grep' ti dà un output un po' come questo:

zone "domain1.tld" { 
zone "domain2.tld" { 
zone "domain3.tld" { 
zone "domain4.tld" { 

Sto indovinando si desidera che l'uscita sia qualcosa di simile, dal momento che ha detto è necessario il testo tra virgolette:

"domain1.tld" 
"domain2.tld" 
"domain3.tld" 
"domain4.tld" 

Quindi, in realtà, da ogni riga vogliamo solo il testo tra le doppie virgolette (comprese le doppie virgolette stesse)

Non sono sicuro che abbiate familiarità con Regular Expressions, ma sono uno strumento inestimabile per ogni persona che scrive script di shell. Ad esempio, l'espressione regolare /.o.e/ corrisponde a qualsiasi riga in cui una parola con la seconda lettera era una minuscola o e la quarta era e. Ciò corrisponderebbe stringa contenente parole come "zone", "tone", o anche "I am tone-deaf."

Il trucco c'era da utilizzare il carattere . (punto) per indicare "qualsiasi lettera". Esistono un paio di altri caratteri speciali, ad esempio * che significa "ripeti il ​​carattere precedente 0 o più volte". Così un'espressione regolare come a* sarebbe partita "a", "aaaaaaa", o una stringa vuota: ""

in modo da poter corrispondere alla stringa all'interno delle virgolette con: /".*"/

C'è un'altra cosa si dovrebbe sapere su sed (e dai commenti, lo fai già!) - consente il backtracking . Una volta che gli hai detto come riconoscere una parola, puoi usare quella parola come parte della sostituzione. Per esempio, diciamo che si voleva trasformare questa lista:

Billy "The Kid" Smith 
Jimmy "The Fish" Stuart 
Chuck "The Man" Norris 

In questa lista:

The Kid 
The Fish 
The Man 

In primo luogo, devi cercare la stringa racchiusa tra virgolette. L'abbiamo già visto, era /".*"/.

Successivamente, vogliamo utilizzare ciò che è racchiuso tra virgolette.Siamo in grado di gruppo utilizzando parentesi: /"(.*)"/

Se volessimo sostituire il testo con le virgolette con un carattere di sottolineatura, ci piacerebbe fare una sostituzione: s/"(.*)"/_/, e che ci avrebbe lasciato con:

Billy _ Smith 
Jimmy _ Stuart 
Chuck _ Norris 

Ma abbiamo il backtracking! Questo ci permetterà di ricordare cosa c'era dentro i paren, usando il simbolo \1. Quindi, se facciamo ora: s/"(.*)"/\1/ ci arriveremo:

Billy The Kid Smith 
Jimmy The Fish Stuart 
Chuck The Man Norris 

Perché le virgolette non erano nelle parentesi, non erano parte del contenuto di \1!

Per lasciare solo il materiale tra virgolette, è necessario abbinare l'intera linea. (. Che significa "fine linea") Per fare questo abbiamo ^ (che significa "all'inizio della linea"), e $

Così ora se usiamo s/^.*"(.*)".*$/\1/, ci arriveremo:

The Kid 
The Fish 
The Man 

Perché? Leggiamo l'espressione regolare s/^.*"(.*)".*$/\1/ da sinistra a destra:

  • s/ - Avviare una sostituzione espressione regolare
  • ^ - Cercare l'inizio della linea. Inizia da lì.
  • .* - Continua ad andare, la lettura di ogni personaggio, fino a quando ...
  • " - ... fino a raggiungere un doppio preventivo.
  • ( - avviare un gruppo di caratteri che potremmo desiderare di richiamare in un secondo momento durante il backtracking.
  • .* - Continua ad andare, la lettura di ogni personaggio, fino a quando ...
  • ) - (!! Pssst chiudere il gruppo)
  • " - ... fino a raggiungere un doppio preventivo.
  • .* - Continua ad andare, la lettura di ogni personaggio, fino a quando ...
  • $ - La fine della linea!

  • / - utilizzare ciò che è dopo questo per sostituire quello che abbinato

  • \1 - incollare il contenuto del primo gruppo (quello che era nelle parentesi) abbinato.
  • / - fine della espressione regolare

In parole povere:. "Leggi l'intera linea, la copia da parte il testo tra le virgolette Poi sostituire l'intera linea con il contenuto tra i doppi qoutes."

È anche possibile aggiungere virgolette doppie attorno al testo sostituendo s/^.*"(.*)".*$/"\1"/, così ci arriveremo:

"The Kid" 
"The Fish" 
"The Man" 

e che può essere usata da sed per sostituire la linea con il contenuto dall'interno delle citazioni:

sed -e "s/^.*\"\(.*\)\".*$/\"\1\"/" 

(questo è solo conchiglia sfuggito a che fare con i doppi apici e barre e roba.)

Così l'intero comando di wo ULD essere qualcosa del tipo:

cat named.local | grep zone | sed -e "s/^.*\"\(.*\)\".*$/\"\1\"/" 
+0

Sì, lo sto usando proprio adesso, ma penso che ci dovrebbe essere un modo più semplice per farlo, perché ora uso sed -e 's/zone "// g' | sed -e 's /" { // g 'per rimuovere l'inizio e la fine di un file invece di corrispondere semplicemente al centro. – jpou

+1

Rasare l'inizio e la fine è perfettamente accettabile. Questo non è un concorso - se funziona, va bene. Se vuoi farlo abbinando il testo tra virgolette, dai un'occhiata ai "gruppi catturanti". – zoul

+0

ugh. Ho passato troppo tempo a scriverlo, e non è ancora finito ... sembra che tutti mi abbiano battuto. Ma sono contento che tu abbia già capito :-) – scraimer

0

Si dovrebbe avere uno sguardo a awk.

1

1.

[email protected]:etc$ cat named.conf | grep zone 
zone "." IN { 
zone "localhost" IN { 
    file "localhost.zone"; 
zone "0.0.127.in-addr.arpa" IN { 

2.

[email protected]:etc$ cat named.conf | grep ^zone 
zone "." IN { 
zone "localhost" IN { 
zone "0.0.127.in-addr.arpa" IN { 

3.

[email protected]:etc$ cat named.conf | grep ^zone | sed 's/.*"\([^"]*\)".*/\1/' 
. 
localhost 
0.0.127.in-addr.arpa 

Anche l'espressione regolare è .*"\([^"]*\)".*, che corrisponde a:

  1. qualsiasi numero di caratteri: .*
    • una citazione: "
    • inizia da ricordare per la successiva: \(
    • qualsiasi carattere tranne preventivo: [^"]*
    • finisce gruppo da ricordare: Quotazione \)
    • chiusura : "
    • e qualsiasi numero di caratteri: .*

Quando si chiama sed, la sintassi è 's/what_to_match/what_to_replace_it_with/'. Le virgolette singole sono lì per impedire che l'espressione regolare venga espansa per bash. Quando si "ricorda" qualcosa nell'espressione utilizzando parenti, è possibile richiamarlo come \1, \2 ecc. Giocare con esso per un po '.

2

Beh, nessuno ha menzionato cut ancora, così, per dimostrare che ci sono molti modi per fare qualcosa con la shell:

% grep '^zone' /etc/bind/named.conf | cut -d' ' -f2 
"gennic.net" 
"generic-nic.net" 
"dyn.generic-nic.net" 
"langtag.net" 
0

Finché qualcuno sta sottolineando sed/awk, ho intenzione di fai notare che grep è ridondante.

sed -ne '/^zone/{s/.*"\([^"]*\)".*/\1/;p}' /etc/bind/named.conf 

Questo ti dà quello che stai cercando senza le virgolette (spostare le citazioni all'interno delle parentesi per tenerli).In awk, è ancora più semplice con le virgolette:

awk '/^zone/{print $2}' /etc/bind/named.conf 

Cerco di evitare condotte il più possibile (ma non di più). Ricorda, Don't pipe cat. Non è necessario E, in quanto awk e sed che duplicano il lavoro di grep, non si canalizzano neppure. Almeno, non in sed o awk.

Personalmente, probabilmente avrei usato Perl. Questo perché probabilmente avrei fatto il resto di quello che stai facendo in perl, rendendolo un dettaglio minore (ed essendo in grado di ingurgitare l'intero file e regex contro tutto simultaneamente, ignorare \ n sarebbe un bonus per i casi in cui Non controllo/etc/bind, come su un webhost condiviso). Ma, se dovessi farlo in shell, uno dei due precedenti sarebbe il modo in cui mi avvicinerei.

Problemi correlati