Commenta tutte le righe dall'ultima riga commentata alla riga con 'pippo'


12

Prendi in considerazione un file di testo users.txt:

#alice
#bob
charlie
dotan
eric

Ho bisogno di commentare tutto (dall'esclusiva) ultima riga commentata fino a (incluso) dotan. Questo è il risultato:

#alice
#bob
#charlie
#dotan
eric

C'è un simpatico sedinterlocutore per farlo? Sarò felice con qualsiasi strumento, non solo sed, davvero.

Attualmente sto ricevendo il numero di riga dell'ultima riga commentata in questo modo:

$ cat -n users.txt | grep '#' | tail -n1
  2 #bob

Aggiungo quindi uno e commento con sed:

$ sed -i'' '3,/dotan/ s/^/#/' users.txt

So che potrei essere intelligente e mettere tutto insieme con alcuni bcin una brutta fodera. Sicuramente ci deve essere un modo più pulito?

Risposte:


5

Che ne dite di

perl -pe '$n=1 if s/^dotan/#$&/; s/^[^#]/#$&/ unless $n==1;' file

o, la stessa idea in awk:

awk '(/^dotan/){a=1; sub(/^/,"#",$1)} (a!=1 && $1!~/^#/){sub(/^/,"#",$1);}1; ' file

7

Se le righe commentate esistenti formano un singolo blocco contiguo, è possibile abbinare invece dalla prima riga commentata, commentando solo quelle righe fino al modello di fine che non sono già commentate e includendo

sed '/^#/,/dotan/ s/^[^#]/#&/' file

Se i commenti esistenti non sono contigui, quindi a causa della natura avida della corrispondenza della gamma sed penso che dovresti fare qualcosa di simile

tac file | sed '/dotan/,/^#/ s/^[^#]/#&/' | tac

cioè abbinare verso l' alto dal modello finale al "primo" commento - ovviamente non è così conveniente se si desidera una soluzione sul posto.


4

Puoi gestire entrambi i casi (righe commentate in un singolo blocco contiguo o intervallate da righe non commentate) con una singola sedchiamata:

sed '1,/PATTERN/{/^#/{x;1d;b};//!{H;/PATTERN/!{1h;d};//{x;s/\n/&#/g}}}' infile

Questo elabora solo le linee 1,/PATTERN/nell'intervallo. Ë xmodifiche tengono spazio w. spazio di pattern ogni volta che viene commentata una riga (quindi non c'è mai più di una riga commentata nel buffer di mantenimento) e aggiunge ogni riga che non è commentata al Hvecchio spazio (quando si trova sulla 1a riga, 1de 1hsono rispettivamente necessari per rimuovere l'iniziale riga vuota nel buffer di conservazione).
Quando raggiunge la linea corrispondente a PATTERN, lo aggiunge anche al Hvecchio buffer, xcambia i buffer e quindi sostituisce ogni \ncarattere di ewline nello spazio di pattern con una \newline e un #(cioè, tutte le linee nello spazio di pattern ora iniziano con #, includendo la prima riga come prima riga nello spazio di attesa è sempre una riga commentata).
Con un campione infile:

alice
#bob
bill
#charlie
ding
dong
dotan
jimmy
#garry

in esecuzione:

sed '1,/dotan/{                   # if line is in this range    -start c1
/^#/{                             # if line is commented        -start c2
x                                 # exchage hold space w. pattern space
1d                                # if 1st line, delete pattern space
b                                 # branch to end of script
}                                 #                             -end c2
//!{                              # if line is not commented    -start c3
H                                 # append to hold space
/dotan/!{                         # if line doesn't match dotan -start c4
1h                                # if 1st line, overwrite hold space
d                                 # delete pattern space
}                                 #                             -end c4
//{                               # if line matches dotan       -start c5
x                                 # exchage hold space w. pattern space
s/\n/&#/g                         # add # after each newline character
}                                 #                             -end c5
}                                 #                             -end c3
}' infile                         #                             -end c1

uscite:

alice
#bob
bill
#charlie
#ding
#dong
#dotan
jimmy
#garry

quindi sta commentando solo le righe da (ed escludendo) #charliefino a (ed incluso) dotane lasciando intatte le altre righe.
Certo, questo presuppone che ci sia sempre almeno una riga commentata prima della corrispondenza della riga PATTERN. In caso contrario, è possibile aggiungere un ulteriore controllo prima della sostituzione:/^#/{s/\n/&#/g}


Grazie, avrò molto da imparare da questa risposta!
dotancohen,

Aspetta, devo aver sbagliato. Non si tratta dell'ultima serie di righe commentate? No, capisco, lo è. L'ultima serie + dotan. Abbastanza intelligente.
Mikeserv,

1
Trovi sempre le domande migliori. Dannato dotan mi ha fatto buttare per un po '- forse lo fa ancora, non l'ho ancora testato. grazie don.
Mikeserv,

2

Eccone un altro sed:

sed  -e:n -e'/\n#.*\ndotan/!{$!{N;/^#/bn'      \
-eb  -e\} -e'/^#/s/\(\n\)\(dotan.*\)*/\1#\2/g' \
-et  -e\} -eP\;D <in >out

Questo fa come chiedi. Funziona solo su uno stack - costruendolo quando necessario e per tutto il tempo necessario tra le occorrenze delle righe commentate e scaricando il vecchio buffer a favore della nuova riga commentata più avanti nell'input quando ne trova una. Immagine...

inserisci qui la descrizione dell'immagine

Scusa, non so perché l'ho fatto. Ma mi è venuto in mente.

Ad ogni modo, seddiffonde i suoi buffer tra ogni ultima riga commentata di qualsiasi serie, non mantenendo mai un singolo più nel suo buffer di quanto sia necessario per tracciare con precisione l'ultima occorrenza commentata, e se in qualsiasi momento incontra l'ultima riga mentre lo fa, tenterà il la gdichiarazione finale di esecuzione lobale e la diramazione di ttutto il buffer da stampare, altrimenti Pstaccherà tutte le righe che rilascia dal suo buffer non appena lo fa.

Immagino sia questo che ha fatto venire in mente le fisarmoniche ...

printf %s\\n   \#alice \#bob charlie dotan eric \
               \#alice \#bob charlie dotan eric \
               \#alice \#bob charlie dotan eric |
sed  -e:n -e'l;/\n#.*\ndotan/!{$!{N;/^#/bn'     \
-eb  -e\} -e'/^#/s/\(\n\)\(dotan.*\)*/\1#\2/g'  \
-et  -e\} -eP\;D

#alice
#alice\n#bob$
#alice\n#bob\ncharlie$
#alice\n#bob\ncharlie\ndotan$
#alice
#bob\ncharlie\ndotan$
#bob\ncharlie\ndotan\neric$
#bob\ncharlie\ndotan\neric\n#alice$
#bob\ncharlie\ndotan\neric\n#alice\n#bob$
#bob\ncharlie\ndotan\neric\n#alice\n#bob\ncharlie$
#bob\ncharlie\ndotan\neric\n#alice\n#bob\ncharlie\ndotan$
#bob
charlie\ndotan\neric\n#alice\n#bob\ncharlie\ndotan$
charlie
dotan\neric\n#alice\n#bob\ncharlie\ndotan$
dotan
eric\n#alice\n#bob\ncharlie\ndotan$
eric
#alice\n#bob\ncharlie\ndotan$
#alice
#bob\ncharlie\ndotan$
#bob\ncharlie\ndotan\neric$
#bob\ncharlie\ndotan\neric\n#alice$
#bob\ncharlie\ndotan\neric\n#alice\n#bob$
#bob\ncharlie\ndotan\neric\n#alice\n#bob\ncharlie$
#bob\ncharlie\ndotan\neric\n#alice\n#bob\ncharlie\ndotan$
#bob
charlie\ndotan\neric\n#alice\n#bob\ncharlie\ndotan$
charlie
dotan\neric\n#alice\n#bob\ncharlie\ndotan$
dotan
eric\n#alice\n#bob\ncharlie\ndotan$
eric
#alice\n#bob\ncharlie\ndotan$
#alice
#bob\ncharlie\ndotan$
#bob\ncharlie\ndotan\neric$
#bob
#charlie
#dotan
eric

C'è solo una differenza tra questo comando e quello sopra e quello è il lcomando ook in alto. Quando abbiamo look a sed's spazio modello come funziona possiamo ottenere una migliore idea di quello che succede dietro le quinte e una migliore comprensione di come indirizzare i propri sforzi.

In questo caso possiamo osservare l' sedinput di stack fino a quando non viene rilevata una seconda occorrenza di \n#.*\ndotaninput, e che quando inizia a stampare la precedente una riga alla volta. È un po 'figo. Ho imparato molto lavorando su questo.


Molto bello grazie! L'ultimo paragrafo con le spiegazioni è formidabile, passerò parecchio tempo anche a imparare da questo post. Bella pila!
dotancohen,

1
@dotancohen - questa è stata davvero una bella domanda. Dai un'occhiata alla modifica per vedere lo stack .
Mikeserv,

2
Ho notato nella cronologia delle modifiche la voce Handle many dotans. Sono sicuro che questo è il peggior incubo di mia moglie.
dotancohen,

1
@dotancohen - sì, è stata dura. Roba come #\ndotan\ndotanè difficile per queste cose. Voglio dire quando dico una buona domanda. Io penso che ho preso quasi perfetto, ma un problema che si potrebbe incorrere in è se i tuoi blocchi di commento sono separati da un 1000 linee - che si rallentarlo. Potresti attaccare qualcosa come s/\n/&/150;tprima della prima /\n#cosa per rompere il buffer se si estende su 150 linee, ad esempio. E comunque, forse è proprio quello che sta aspettando da sempre !
Mikeserv,
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.