Estoy de acuerdo con usted, probablemente sea un problema genérico. Sin embargo, algunas utilidades comunes tienen algunas facilidades para manejarlo.
nl
nl
, por ejemplo, separa la entrada en páginas lógicas como -d
eliminadas por un delimitador de sección de dos caracteres . Tres apariciones en una línea indican el comienzo de un encabezado , dos el cuerpo y uno el pie de página . Reemplaza cualquiera de estos que se encuentran en la entrada con una línea en blanco en la salida, que son las únicas líneas en blanco que imprime
Modifiqué tu ejemplo para incluir otra sección y ponerlo ./infile
. Entonces se ve así:
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
Luego ejecuté lo siguiente:
sed 's/^@@.*start$/@@@@@@/
s/^@@.*end$/@@/' <infile |
nl -d@@ -ha -bn -w1
nl
se le puede decir que acumule estado en las páginas lógicas, pero no lo hace de manera predeterminada. En su lugar, numerará las líneas de su entrada de acuerdo con los estilos y por sección . Entonces -ha
significa numerar todas las líneas de encabezado y -bn
significa que no hay líneas de cuerpo , ya que comienza en un cuerpo estado de .
Hasta que aprendí esto, solía usarlo nl
para cualquier entrada, pero después de darme cuenta de que nl
podría distorsionar la salida de acuerdo con su -d
eliminador predeterminado \:
, aprendí a ser más cuidadoso con él y comencé a usarlo grep -nF ''
para la entrada no probada. Pero otra lección aprendida ese día fue que nl
se puede aplicar de manera muy útil en otros aspectos, como este, si solo modifica un poco su entrada, como hago consed
anterior.
SALIDA
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
Aquí hay más información nl
: ¿observan cómo todas las líneas, excepto las numeradas, comienzan con espacios? Cuando las nl
líneas de números inserta un cierto número de caracteres en la cabeza de cada uno. Para esas líneas no -w
numera , incluso espacios en blanco, siempre coincide con la sangría insertando ( idth count + -s
eparator len) * espacios en la parte superior de las líneas sin numerar. Esto le permite reproducir el contenido no numerado exactamente comparándolo con el contenido numerado, y con poco esfuerzo. Cuando considere que nl
dividirá su entrada en secciones lógicas para usted y que puede insertar -s
trings arbitrarios en la cabecera de cada línea que numere, entonces se vuelve bastante fácil manejar su salida:
sed 's/^@@.*start$/@@@@@@/
s/^@@.*end/@@/; t
s/^\(@@\)\{1,3\}$/& /' <infile |
nl -d@@ -ha -bn -s' do something with the next line!
'
Las impresiones anteriores ...
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
ÑU sed
Si nl
no es su aplicación de destino, un GNU sed
puede e
ejecutar un comando de shell arbitrario en función de una coincidencia.
sed '/^@@.*start$/!b
s//nl <<\\@@/;:l;N
s/\(\n@@\)[^\n]*end$/\1/
Tl;e' <infile
Arriba sed
recoge la entrada en el espacio del patrón hasta que tenga suficiente para pasar con éxito el T
est de sustitución y dejar de b
volver a la :l
granja. Cuando lo hace, se e
ejecuta nl
con una entrada representada como un<<
documento aquí para todo el resto de su espacio de patrones.
El flujo de trabajo es así:
/^@@.*start$/!b
- Si una
^
línea entera $
no !
no /
coincide con /
el patrón anterior, entonces se b
ranched fuera del guión y autoprinted - por lo que a partir de ahora sólo estamos trabajando con una serie de líneas que se inició con el patrón.
s//nl <<\\@@/
- el
s//
campo vacío /
representa la última dirección que sed
intentó coincidir, por lo que este comando sustituye la @@.*start
línea completa en su nl <<\\@@
lugar.
:l;N
- El
:
comando define una etiqueta de rama: aquí configuro uno llamado :l
abel. El N
comando ext agrega la siguiente línea de entrada al espacio de patrón seguido de un \n
carácter de línea de flujo. Esta es una de las pocas formas de obtener un \n
ewline en un sed
espacio de patrón: el \n
carácter ewline es un delimitador seguro para un sed
der que lo ha estado haciendo durante un tiempo.
s/\(\n@@\)[^\n]*end$/\1/
- esta
s///
ubicación solo puede tener éxito después de encontrar un inicio y solo en la primera aparición posterior de una línea final . Solo actuará en un espacio de patrón en el que la línea de \n
ew final es seguida inmediatamente @@.*end
marcando el final $
del espacio de patrón. Cuando actúa, reemplaza toda la cadena coincidente con el \1
primer \(
grupo \)
, o \n@@
.
Tl
- el
T
comando est se bifurca a una etiqueta (si se proporciona) si no se ha producido una sustitución exitosa desde la última vez que se introdujo una línea de entrada en el espacio del patrón (como lo hago w / N
) . Esto significa que cada vez que \n
se agrega una línea ew al espacio de patrón que no coincide con su delimitador final, el T
comando est falla y se bifurca de nuevo al :l
abel, lo que resulta en sed
tirar de la N
línea ext y hacer un bucle hasta que tenga éxito.
e
Cuando la sustitución de la coincidencia final sea exitosa y la secuencia de comandos no se ramifique para una prueba fallida T
, sed
se e
ejecutará un comando que l
tenga este aspecto:
nl <<\\@@\nline X\nline Y\nline Z\n@@$
Puedes ver esto por ti mismo editando la última línea para que se vea Tl;l;e
.
Imprime:
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
Una última forma de hacer esto, y quizás la más simple, es usar un while read
bucle, pero por una buena razón. El shell - (más especialmente un bash
shell) - es típicamente bastante abismal al manejar la entrada en grandes cantidades o en flujos estables. Esto también tiene sentido: el trabajo del shell es manejar el ingreso de caracteres por carácter y llamar otros comandos que pueden manejar las cosas más grandes.
Pero lo más importante acerca de su función es que el shell no debe read
sobrepasar la entrada: se especifica que no amortigua la entrada o salida hasta el punto que consume tanto o no se retransmite lo suficiente como para que falten los comandos que llama. - al byte. Por read
lo tanto, es una excelente prueba de entrada :return
obtener información sobre si hay entrada restante y debe llamar al siguiente comando para leerla, pero por lo general, no es la mejor manera de hacerlo.
Aquí hay un ejemplo, sin embargo, de cómo uno podría usar read
y otros comandos para procesar la entrada sincronizada:
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
Lo primero que sucede para cada iteración son los read
tirones en una línea. Si tiene éxito, significa que el bucle aún no ha llegado a EOF y, por lo tanto, case
si coincide con un delimitador de inicio, el do
bloque se ejecuta inmediatamente. Si no, printf
imprime el $line
que read
y sed
se llama.
sed
se p
rint cada línea hasta que se encuentra con el inicio marcador - cuando q
UITS de entrada por completo. El -u
conmutador nbuffered es necesario para GNU sed
porque de lo contrario puede almacenarse en búfer con bastante avidez, pero, según las especificaciones, otros POSIX sed
deberían funcionar sin ninguna consideración especial, siempre que <infile
sea un archivo normal.
Cuando se sed
q
inicia por primera vez, el shell ejecuta el do
bloque del bucle, que llama a otro sed
que imprime cada línea hasta que encuentra el marcador final . Canaliza su salida a paste
, porque imprime los números de línea cada uno en su propia línea. Me gusta esto:
1
line M
2
line N
3
line O
paste
luego los pega juntos en los :
caracteres, y toda la salida se ve así:
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
Estos son solo ejemplos: aquí se puede hacer cualquier cosa en la prueba o en los bloques, pero la primera utilidad no debe consumir demasiada información.
Todas las utilidades involucradas leen la misma entrada, e imprimen sus resultados, cada una a su vez. Este tipo de cosas puede ser difícil de conseguir la caída de - debido a diferentes utilidades serán amortiguar más que otros - pero en general se puede confiar en dd
, head
y sed
hacer lo correcto (aunque, para GNU sed
, se necesita el cli-switch) y siempre debe poder confiar read
, porque es, por naturaleza, muy lento . Y es por eso que el ciclo anterior lo llama solo una vez por bloque de entrada.
nl
No tiene que acumular estado . Mirenl -d
y comprobar suman
/info
páginas de información sobrenl
's sección delimitador .