Leer un archivo completo en el espacio de patrones es útil para sustituir nuevas líneas, & c. y hay muchas instancias que aconsejan lo siguiente:
sed ':a;N;$!ba; [commands...]'
Sin embargo, falla si la entrada contiene solo una línea.
Como ejemplo, con dos entradas de línea, cada línea está sujeta al comando de sustitución:
$ echo $'abc\ncat' | sed ':a;N;$!ba; s/a/xxx/g'
xxxbc
cxxxt
Pero, con una sola entrada de línea, no se realiza ninguna sustitución:
$ echo 'abc' | sed ':a;N;$!ba; s/a/xxx/g'
abc
¿Cómo se escribe un sedcomando para leer todas las entradas a la vez y no tener este problema?

sed -zopción de GNU . Si su archivo no tiene nulo, ¡se leerá hasta el final del archivo! Encontrado en esto: stackoverflow.com/a/30049447/582917Respuestas:
Hay todo tipo de razones por las cuales leer un archivo completo en el espacio de patrones puede salir mal. El problema lógico en la pregunta que rodea la última línea es común. Está relacionado con
sedel ciclo de línea de - cuando no hay más líneas ysedencuentra EOF a través - termina el procesamiento. Entonces, si está en la última línea y le indicasedque obtenga otra, se detendrá allí y no hará más.Dicho esto, si realmente necesita leer un archivo completo en el espacio de patrones, entonces probablemente valga la pena considerar otra herramienta de todos modos. El hecho es que
sedes el mismo nombre del editor de flujo , está diseñado para trabajar una línea, o un bloque de datos lógico, a la vez.Hay muchas herramientas similares que están mejor equipadas para manejar bloques de archivos completos.
edyex, por ejemplo, puede hacer mucho de lo quesedpuede hacer y con una sintaxis similar, y mucho más, pero en lugar de operar solo en una secuencia de entrada mientras se transforma en salidased, también mantienen archivos de respaldo temporales en el sistema de archivos . Su trabajo se almacena en el disco según sea necesario, y no se cierra abruptamente al final del archivo (y tiende a explotar con mucha menos frecuencia bajo la tensión del búfer) . Además, ofrecen muchas funciones útiles quesedno lo hacen, del tipo que simplemente no tiene sentido en un contexto de flujo, como marcas de línea, deshacer, búferes con nombre, unirse y más.sedLa fortaleza principal es su capacidad para procesar datos tan pronto como los lee, de manera rápida, eficiente y en tiempo real. Cuando sorbe un archivo, lo tira y tiende a encontrarse con dificultades de caso límite como el problema de la última línea que menciona, desbordamientos de búfer y rendimiento abismal, a medida que los datos que analiza crecen en longitud el tiempo de procesamiento de un motor de expresiones regulares al enumerar coincidencias aumenta exponencialmente .Con respecto a este último punto, por cierto: si bien entiendo que el
s/a/A/gcaso de ejemplo es muy probable que sea solo un ejemplo ingenuo y probablemente no sea el guión real para el que desea recopilar una entrada, es posible que valga la pena familiarizarse cony///. Si a menudo te encuentrasgsustituyendo a nivel mundial un solo personaje por otro, entoncesypodría ser muy útil para ti. Es una transformación en lugar de una sustitución y es mucho más rápido, ya que no implica una expresión regular. Este último punto también puede ser útil cuando se intenta preservar y repetir//direcciones vacías porque no las afecta pero puede verse afectada por ellas. En cualquier caso,y/a/A/es un medio más simple de lograr lo mismo, y los intercambios también son posibles como:y/aA/Aa/que intercambiarían todas las mayúsculas / minúsculas como en una línea entre sí.También debe tener en cuenta que el comportamiento que describe realmente no es lo que se supone que debe suceder de todos modos.
De GNU
info seden la sección ERRORES COMUNES REPORTADOS :Ncomando en la última líneaLa mayoría de las versiones de
sedexit sin imprimir nada cuando elNcomando se emite en la última línea de un archivo. GNUsedimprime el espacio del patrón antes de salir a menos que, por supuesto,-nse haya especificado el interruptor de comando. Esta elección es por diseño.Por ejemplo, el comportamiento de
sed N foo bardependería de si foo tiene un número par o impar de líneas. O, al escribir un script para leer las siguientes líneas después de una coincidencia de patrones, las implementaciones tradicionales desedte obligarían a escribir algo así en/foo/{ $!N; $!N; $!N; $!N; $!N; $!N; $!N; $!N; $!N }lugar de solo/foo/{ N;N;N;N;N;N;N;N;N; }.En cualquier caso, la solución más simple es usar
$d;Nscripts que se basen en el comportamiento tradicional, o establecer laPOSIXLY_CORRECTvariable en un valor no vacío.La
POSIXLY_CORRECTvariable de entorno se menciona porque POSIX especifica que sisedencuentra EOF al intentarloN, debe salir sin salida, pero la versión GNU rompe intencionalmente con el estándar en este caso. Tenga en cuenta también que, aunque el comportamiento se justifica por encima de la suposición, es que el caso de error es uno de edición de flujo, no de arrastrar un archivo completo a la memoria.El estándar define
Nel comportamiento de la siguiente manera:NAgregue la siguiente línea de entrada, menos su línea de
\new final , al espacio del patrón, utilizando una\nlínea de ew incrustada para separar el material adjunto del material original. Tenga en cuenta que el número de línea actual cambia.Si no hay disponible la siguiente línea de entrada, el
Nverbo de comando se bifurcará hasta el final del script y se cerrará sin comenzar un nuevo ciclo o copiar el espacio del patrón a la salida estándar.En esa nota, hay otros GNU-ismos demostrados en la pregunta, particularmente el uso de la
:etiqueta,brancho y{corchetes de contexto de función}. Como regla general,sedse entiende que cualquier comando que acepte un parámetro arbitrario se delimita en una línea\nelectrónica en el script. Entonces los comandos ...... es muy probable que funcionen de manera errática dependiendo de la
sedimplementación que los lea. Portablemente deben escribirse:Lo mismo es cierto para
r,w,t,a,i, yc(y, posiblemente, un poco más que yo estoy olvidando por el momento) . En casi todos los casos, también podrían escribirse:... donde la nueva
-einstrucción xecution representa el\ndelimitador de la línea ew. Entonces, cuando elinfotexto de GNU sugiere que una implementación tradicionalsedlo obligaría a hacer :... más bien debería ser ...
... por supuesto, eso tampoco es cierto. Escribir el guión de esa manera es un poco tonto. Hay medios mucho más simples para hacer lo mismo, como:
... que imprime:
... porque el
tcomando est, como la mayoría de lossedcomandos, depende del ciclo de línea para actualizar su registro de retorno y aquí el ciclo de línea puede realizar la mayor parte del trabajo. Esa es otra compensación que realiza cuando sorbe un archivo: el ciclo de la línea no se actualiza nunca más y muchas pruebas se comportarán de manera anormal.El comando anterior no se arriesga a una entrada exagerada porque solo hace algunas pruebas simples para verificar lo que lee mientras lo lee. Con
Hantiguo, todas las líneas se agregan al espacio de espera, pero si una línea coincide/foo/, sobrescribe elhespacio antiguo. Los búferes sexcambian a continuación, ys///se intenta una sustitución condicional si el contenido del búfer coincide con el//último patrón abordado. En otras palabras,//s/\n/&/3pintenta reemplazar la tercera nueva línea en el espacio de espera consigo mismo e imprime los resultados si el espacio de espera coincide actualmente/foo/. Si eso tienetéxito, el guión se ramifica a la etiquetanotdelete, que hace unlook y termina el guión.Sin
/foo/embargo, en el caso de que ambas y una tercera línea nueva no puedan coincidir en el espacio de espera,//!gsobrescribirán el búfer si/foo/no coincide, o, si coincide, sobrescribirá el búfer si una línea\new no coincide (reemplazando así/foo/con en sí) . Esta pequeña prueba sutil evita que el búfer se llene innecesariamente durante largos períodos de no/foo/y garantiza que el proceso se mantenga ágil porque la entrada no se acumula. Continuando en un caso de no/foo/o//s/\n/&/3pfalla, los buffers se intercambian nuevamente y se eliminan todas las líneas, excepto la última.Esa última, la última línea
$!d, es una demostración simple de cómosedse puede hacer un script de arriba hacia abajo para manejar múltiples casos fácilmente. Cuando su método general es eliminar los casos no deseados, comenzando por los más generales y trabajando hacia los más específicos, los casos límite se pueden manejar más fácilmente porque simplemente se les permite llegar hasta el final del script con sus otros datos deseados y cuándo todo se envuelve y te quedan solo los datos que deseas. Sin embargo, tener que recuperar estos casos extremos de un circuito cerrado puede ser mucho más difícil de hacer.Y aquí está lo último que tengo que decir: si realmente debe extraer un archivo completo, entonces puede soportar hacer un poco menos de trabajo confiando en el ciclo de línea para hacerlo por usted. Normalmente se usaría
Next ynextensión de búsqueda hacia delante - debido a que avanzan por delante del ciclo de línea. En lugar de implementar redundantemente un bucle cerrado dentro de un bucle, ya que elsedciclo de línea es solo un bucle de lectura simple de todos modos, si su propósito es solo reunir información indiscriminadamente, entonces probablemente sea más fácil de hacer:... que reunirá todo el archivo o lo intentará.
una nota al margen sobre
Nel comportamiento de la última línea ...fuente
Hprimero es encantador.:a;$!{N;ba}como mencioné anteriormente: es más fácil usar la forma estándar a largo plazo cuando intentas ejecutar expresiones regulares en sistemas desconocidos. Pero eso no era realmente lo que quise decir: implementas un ciclo cerrado, no puedes meterte tan fácilmente en el medio cuando lo desees como lo harías, ramificando, recortando datos no deseados y dejando que el ciclo suceda. Es como una cosa de arriba hacia abajo: todo lo quesedhace es un resultado directo de lo que acaba de hacer. Tal vez lo veas de manera diferente, pero si lo intentas, es posible que el script sea más fácil.Falla porque el
Ncomando viene antes de la coincidencia de patrón$!(no la última línea) y sed se cierra antes de realizar cualquier trabajo:Esto también se puede solucionar fácilmente para que funcione con entrada de una sola línea (y, de hecho, para ser más claro en cualquier caso) simplemente agrupando los comandos
Nybdespués del patrón:Funciona de la siguiente manera:
:acrear una etiqueta llamada 'a'$!si no es la última línea, entoncesNagregue la siguiente línea al espacio del patrón (o salga si no hay una línea siguiente) ybabifurque (vaya a) la etiqueta 'a'Desafortunadamente, no es portátil (ya que se basa en extensiones GNU), pero la siguiente alternativa (sugerida por @mikeserv) es portátil:
fuente
:a;N;$!ba;.