È possibile abbinare più numeri di riga specifici (non intervallo) con sed?


9

Prendere in considerazione:

echo -e "a\nb\nc\nd\ne\nf\ng\nh" | sed '3,5a test'

Questo corrisponderà alle linee 3, 4 e 5.

Ma sto cercando di abbinare solo le linee 3 e 5 (non 4). E aggiungi 'test' dopo di loro.

Risposte:


9
echo ... | sed -e '3a test' -e '5a test'

Se l'operazione è più complessa rispetto a questo caso, è possibile utilizzare una struttura come questa:

sed 'b pattern; : action; a \
lalala
b end; : pattern; 3b action; 5b action; : end'

Cioè hai messo tutti i comandi necessari tra b pattern;e b end;.

E dopo aggiungi tutti i tuoi modelli (numeri di riga o altro) : pattern;.

Quello che succede è questo:

  1. Il primo comando salta sopra la parte azione (forse è più facile leggere se i modelli sono all'inizio e b end;direttamente prima della parte azione).

  2. Se un modello corrisponde, l'esecuzione salta alla parte azione. Al termine dell'esecuzione della parte azione si passa alla fine.

Provo a riordinare questo:

sed '3b action; 5b action; b end; : action; a \
lalala
: end'

In una sola riga sarebbe come:

sed "3b idAction; 5b idAction; b; : idAction; a test"

Portabilmente, devi scriverlo:

sed '
   3b action
   5b action
   b
   : action
   a\
   lalala'

( bsenza i rami dell'etichetta fino alla fine, quindi non è necessaria un'etichetta esplicita end, ;è valido un carattere in un'etichetta nelle sedimplementazioni standard ).


4
Wow, sed subroutine. Fantastico
Glenn Jackman,

Caspita, potresti ampliarli? Sembrano davvero utili!
terdon

quello con 'pattern' e 'action' sembra molto buono in quanto non ho bisogno di ripetere 'test' (o 'lalala'), devo capire ancora meglio grazie! :)
Aquarius Power il

@terdon Cosa potrei?
Hauke ​​Laging,

Volevo dire che il secondo sembra fantastico, ma è difficile da capire e se hai tempo, apprezzerei una spiegazione.
terdon

5

Con sed(vedi la risposta di @ HaukeLaging )

Con awk:

$ echo -e "a\nb\nc\nd\ne\nf\ng\nh" | awk 'NR==3 || NR==5{$0=$0"\ntest"}1;'

Con perl:

$ echo -e "a\nb\nc\nd\ne\nf\ng\nh" | perl -pe '$_ .="test\n" if $. == 3 || $. == 5'

Puoi giocare un po 'a golf, usando l'operatore "partita intelligente":perl -lnE 'say if $. ~~ @{[3,5]}'
glenn jackman,

@glennjackman ah, sì, grazie. Devo ammettere che sono un po 'diffidente ~~, non capisco bene come dovrei. Inoltre, entrambi saye hanno ~~bisogno di perl v> = 5.10 giusto?
terdon

Ho bisogno di aggiungere 'test' dopo quelle righe, vedo ora sarebbe stato meglio chiarirlo sin dall'inizio. Ho appena modificato l'OP.
Aquarius Power il

@AquariusPower, perl -pE 'say "test" if $. ~~ @{[4,6]}'- questo antepone la riga: perl -pfa una stampa implicita alla fine del programma dato.
Glenn Jackman,

@AquariusPower vede anche la risposta aggiornata.
terdon

3

Come ha detto @HaukeLaging aleady, questo comando fa quello che vuoi:

sed -e'3a test' -e'5a test'

Ora, questo può diventare piuttosto ingombrante da digitare se si desidera abbinare, ad esempio, 20 righe.

In questi casi, supponendo che la shell supporti l' espansione del controvento , è possibile utilizzare questo comando invece:

sed -e{3,5}'a test'

(Nota che le parentesi graffe e la virgola devono rimanere non quotate.)

Come risultato, la shell passerà gli argomenti -e3a teste -e5a testdi sed, che è esattamente ciò che il primo comando fa.

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.