Sopprimere le righe con awk


1

Ho una variabile Bash multilinea: $WORDScontenente una parola su ogni riga.
Ho un'altra variabile Bash multilinea: $LISTcontenente anche una parola su ogni riga.

Voglio eliminare $LISTda qualsiasi parola presente in $WORDS.

Attualmente lo faccio con un while reade grepma questo non è sexy.

WORDS=$(echo -e 'cat\ntree\nearth\nred')
LIST=$(echo -e 'abcd\n1234\nred\nwater\npage\ncat')
while read -r LINE; do
    LIST=$(echo "$LIST" | grep -v "$LINE")
done <<< "$WORDS"
echo "$LIST"

Penso di poterlo fare con awkma non sono riuscito a farlo funzionare.
Qualcuno può spiegarmi come farlo con Awk?

Risposte:


3

Questo dovrebbe realizzare ciò che stai cercando di fare.

WORDS=$(echo -e 'cat\ntree\nearth\nred')
LIST=$(echo -e 'abcd\n1234\nred\nwater\npage\ncat')

echo "$LIST" | awk -v WORDS="$WORDS" '
BEGIN {
  split(WORDS,w1,"\n")
  for (w in w1) { w2[w1[w]] = 1 }
}
{
  if (w2[$0] != 1) { print $0 }
}'

Ecco come funziona. Per prima cosa sto usando l' -vopzione nella riga di comando di awk per passare l'elenco di parole come variabile. Questa variabile sarà visibile all'interno del programma awk con il nome WORDS.

Il blocco BEGIN viene eseguito prima dell'elaborazione di qualsiasi input. Contiene due righe

split(WORDS,w1,"\n")

Questo comando diviso prende l'elenco WORDS e lo trasforma in un array chiamato w1.

for (w in w1) { w2[w1[w]] = 1 }

Questo per il ciclo percorre l'array w1 e genera un array associativo chiamato w2. La conversione dell'array in un array associativo migliorerà le prestazioni.

Successivamente abbiamo il corpo principale del loop che elabora la LISTA.

if (w2[$0] != 1) { print $0 }

Ciò controllerà ogni riga di input rispetto al nostro array associativo e stamperà la riga solo se la parola non è stata trovata. Poiché abbiamo assegnato ogni chiave a 1 nel nostro blocco BEGIN, dobbiamo solo verificare se il valore di quella chiave è uguale a 1 per sapere se è definito.


2

suggerisco

echo "$LIST" | grep -vf <(echo "$WORDS")

Fai attenzione a questo dato che grep corrisponderà anche alle sottostringhe. Ad esempio, se "cat" è nell'elenco $ WORDS, filtrerà non solo il gatto, ma anche la categoria, il bestiame, il vacante, ecc. Se puoi aggiungere ^ e $ a ogni parola dovrebbe funzionare. Prova questo:echo "$LIST" | grep -vf <(echo "$WORDS" | sed -re 's/(.*)/^\1$/')
virtex,

1
Oppure grep -x, se questo è un problema.
Michael Vehrs,

Molto bella risposta, grazie. La domanda riguardava Awk, quindi ho selezionato la risposta corrispondente, ma ho usato la tua risposta.
Gregory MOUSSAT,
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.