Sono d'accordo con te - probabilmente è un problema generico. Tuttavia, alcune utility comuni hanno alcune funzionalità per gestirlo.
nl
nl, ad esempio, separa l'input in pagine logiche come -deliminato da un delimitatore di sezione a due caratteri . Tre occorrenze su una riga indicano da sole l'inizio di un'intestazione , due il corpo e uno il piè di pagina . Sostituisce uno qualsiasi di questi trovati nell'input con una riga vuota nell'output - che sono le uniche righe vuote che abbia mai stampato
Ho modificato il tuo esempio per includere un'altra sezione e inserirlo ./infile. Quindi sembra così:
line A
line B
@@inline-code-start
line X
line Y
line Z
@@inline-code-end
line C
line D
@@start
line M
line N
line O
@@end
Quindi ho eseguito il seguente:
sed 's/^@@.*start$/@@@@@@/
s/^@@.*end$/@@/' <infile |
nl -d@@ -ha -bn -w1
nlsi può dire di accumulare stato attraverso pagine logiche, ma non per impostazione predefinita. Invece numererà le linee del suo input secondo gli stili e per sezione . Quindi -hasignifica numerare tutte le linee di intestazione e -bnsignifica nessuna linea del corpo - come inizia in un corpo dello Stato.
Fino a quando non l'ho imparato, lo usavo nl per qualsiasi input, ma dopo aver realizzato che ciò nlpoteva distorcere l'output in base al suo -delimitatore predefinito, \:ho imparato a stare più attento e ho iniziato a utilizzare l' grep -nF ''input non testato. Ma un'altra lezione appresa quel giorno è stata che nlpuò essere utilmente applicato sotto altri aspetti - come questo - se modifichi solo un po 'il suo input - come faccio sedsopra.
PRODUZIONE
line A
line B
1 line X
2 line Y
3 line Z
line C
line D
1 line M
2 line N
3 line O
Ecco qualcosa in più nl: noti sopra come tutte le linee tranne quelle numerate iniziano con gli spazi? Quando le nllinee dei numeri inserisce un certo numero di caratteri nella testa di ciascuno. Per quelle righe non numera - nemmeno gli spazi vuoti - corrisponde sempre al rientro inserendo (-w numera idth count + eparator -slen) * spazi all'inizio di linee non numerate. Ciò consente di riprodurre esattamente il contenuto non numerato confrontandolo con il contenuto numerato e con poco sforzo. Se consideri che nldividerà il suo input in sezioni logiche per te e che puoi inserire -sstringhe arbitrarie all'inizio di ogni riga che numera, allora diventa abbastanza facile gestire il suo output:
sed 's/^@@.*start$/@@@@@@/
s/^@@.*end/@@/; t
s/^\(@@\)\{1,3\}$/& /' <infile |
nl -d@@ -ha -bn -s' do something with the next line!
'
Le stampe sopra ...
line A
line B
1 do something with the next line!
line X
2 do something with the next line!
line Y
3 do something with the next line!
line Z
line C
line D
1 do something with the next line!
line M
2 do something with the next line!
line N
3 do something with the next line!
line O
GNU sed
Se nlnon è l'applicazione di destinazione, una GNU sedpuò eeseguire un comando di shell arbitrario per te a seconda di una corrispondenza.
sed '/^@@.*start$/!b
s//nl <<\\@@/;:l;N
s/\(\n@@\)[^\n]*end$/\1/
Tl;e' <infile
Sopra sedraccoglie input nello spazio modello fino a quando non ha abbastanza per passare con successo l' Test di sostituzione e interrompere bil :lranching all'abel. Quando lo fa, viene eelaborato nlcon input rappresentato come un <<documento qui per tutto il resto del suo spazio-modello.
Il flusso di lavoro è così:
/^@@.*start$/!b
- se un
^intera linea $non !non /corrisponde /al modello di cui sopra, allora è bun ranch fuori dalla sceneggiatura e autoprinted - quindi da questo punto in poi stiamo lavorando solo con una serie di linee che ha avuto inizio con il modello.
s//nl <<\\@@/
- il
s//campo vuoto sostituisce l' /ultimo indirizzo sedtentato di corrispondere, quindi questo comando sostituisce invece l'intera @@.*startriga nl <<\\@@.
:l;N
- Il
:comando definisce un'etichetta di ramo - qui ho impostato uno chiamato :label. Il Ncomando ext aggiunge la riga successiva di input allo spazio pattern seguito da un \ncarattere ewline. Questo è uno dei pochi modi per ottenere una \newline in uno sedspazio modello: il \npersonaggio ewline è un delimitatore sicuro per un sedder che lo ha fatto per un po '.
s/\(\n@@\)[^\n]*end$/\1/
- questo
s///ubstitution può avere successo soltanto dopo un avvio viene rilevato e solo sulla prima a seguito del verificarsi di un fine linea. \nAgirà solo su uno spazio modello in cui la linea finale finale è immediatamente seguita @@.*endcontrassegnando la fine $dello spazio modello. Quando agisce, sostituisce l'intera stringa corrispondente con il \1primo \(gruppo \)o \n@@.
Tl
- il
Tcomando est si ramifica su un'etichetta (se fornita) se non si è verificata una sostituzione riuscita dall'ultima volta in cui una riga di input è stata trascinata nello spazio modello (come faccio io con / N) . Ciò significa che ogni volta che una \newline viene aggiunta allo spazio del pattern che non corrisponde al delimitatore finale, il Tcomando est ha esito negativo e si ramifica di nuovo :lsull'abel, il che si traduce in sedpull in Next line e looping fino al successo.
e
Quando la sostituzione per la partita finale è successo e lo script non lo fa di nuovo ramo per un fallito Test, sedsarà execute un comando che looks come questo:
nl <<\\@@\nline X\nline Y\nline Z\n@@$
Puoi vederlo da solo modificando l'ultima riga lì per apparire Tl;l;e.
Stampa:
line A
line B
1 line X
2 line Y
3 line Z
line C
line D
1 line M
2 line N
3 line O
while ... read
Un ultimo modo per farlo, e forse il modo più semplice, è usare un while readloop, ma per una buona ragione. La shell - (soprattutto una bashshell) - è in genere piuttosto spaventosa nel gestire input in grandi quantità o in flussi costanti. Anche questo ha senso: il lavoro della shell è gestire l'input carattere per carattere e richiamare altri comandi in grado di gestire le cose più grandi.
Ma soprattutto sul suo ruolo c'è che la shell non deve read sovrastare gran parte dell'input - è specificato per non bufferizzare l'input o l'output al punto che consuma così tanto o non trasmette abbastanza nel tempo che i comandi che chiama rimangono mancanti - al byte. Quindi readrende un test di input eccellente - per returninformazioni sulla presenza di input rimanenti e si dovrebbe richiamare il comando successivo per leggerlo - ma in genere non è il modo migliore di procedere.
Ecco un esempio, tuttavia, di come si potrebbero usare read e altri comandi per elaborare l'input in sincronia:
while IFS= read -r line &&
case $line in (@@*start) :;; (*)
printf %s\\n "$line"
sed -un "/^@@.*start$/q;p";;
esac;do sed -un "/^@@.*end$/q;=;p" |
paste -d: - -
done <infile
La prima cosa che accade per ogni iterazione è readuna riga. Se ha esito positivo significa che il loop non ha ancora colpito EOF e quindi nel casecorrispondente delimitatore di avvio il doblocco viene immediatamente eseguito. Altrimenti, printfstampa $linel'esso reade sedsi chiama.
sedsi pRint ogni riga finché non incontra l' inizio marcatore - quando qUITS ingresso interamente. Lo -uswitch nbuffered è necessario per GNU sedperché altrimenti può bufferizzare avidamente, ma - secondo le specifiche - altri POSIX seddovrebbero funzionare senza alcuna considerazione speciale - purché <infilesia un file normale.
Quando il primo viene sed qattivato, la shell esegue il doblocco del loop, che chiama un altro sedche stampa ogni riga fino a quando non incontra il marker di fine . Inoltra il suo output a paste, perché stampa i numeri di riga ciascuno sulla propria riga. Come questo:
1
line M
2
line N
3
line O
pastequindi li incolla sui :personaggi e l'intero output appare come:
line A
line B
1:line X
2:line Y
3:line Z
line C
line D
1:line M
2:line N
3:line O
Questi sono solo esempi: qui si può fare qualsiasi cosa nel test o fare blocchi, ma la prima utility non deve consumare troppo input.
Tutte le utility coinvolte leggono lo stesso input - e stampano i loro risultati - ognuna a turno. Questo genere di cose può essere difficile da ottenere il blocco di - perché diversi programmi di utilità saranno tamponare più di altri - ma si possono generalmente contare su dd, heade seddi fare la cosa giusta (anche se, per GNU sed, è necessario il cli-switch) e dovresti sempre essere in grado di fare affidamento read, perché per sua natura è molto lento . Ed è per questo che il loop sopra lo chiama solo una volta per blocco di input.
nlnon deve accumulare stato . Guardatenl -de controllare leman/infopagine per le informazioni sulnl's delimitatore sezione .