¿Cómo evito que sed agregue caracteres adicionales de nueva línea?

17

Estoy ejecutando los siguientes 2 sedcomandos. El primero agrega caracteres de nueva línea donde los quiero, el segundo también agrega caracteres de nueva línea donde los quiero, PERO también agrega uno adicional al final del archivo donde antes no había ninguno.

sed -e 's|\<LIST_G_STATEMENT>|&\
|g' ${XMLDIR}/statement_tmp_1.xml > ${XMLDIR}/statement_tmp_2.xml

sed -e 's|\</LIST_G_STATEMENT>|&\
|g' ${XMLDIR}/statement_tmp_2.xml > ${XMLDIR}/statement_tmp_3.xml

El uso od -cen los 3 archivos proporciona el siguiente resultado.

Statement_tmp_1.xml (no \nal final del archivo)

1314700    T   A   T   E   M   E   N   T   >   <   /   L   I   S   T   _
1314720    G   _   S   T   A   T   E   M   E   N   T   >   <   /   G   _
1314740    S   E   T   U   P   >   <   /   L   I   S   T   _   G   _   S
1314760    E   T   U   P   >   <   /   A   R   X   S   G   P   O   >
1314777

Statement_tmp_2.xml (no \nal final del archivo)

1314700    S   T   A   T   E   M   E   N   T   >   <   /   L   I   S   T
1314720    _   G   _   S   T   A   T   E   M   E   N   T   >   <   /   G
1314740    _   S   E   T   U   P   >   <   /   L   I   S   T   _   G   _
1314760    S   E   T   U   P   >   <   /   A   R   X   S   G   P   O   >
1315000

Statement_tmp_3.xml ( \nal final del archivo, ¿de dónde vino?)

1314700    S   T   A   T   E   M   E   N   T   >   <   /   L   I   S   T
1314720    _   G   _   S   T   A   T   E   M   E   N   T   >  \n   <   /
1314740    G   _   S   E   T   U   P   >   <   /   L   I   S   T   _   G
1314760    _   S   E   T   U   P   >   <   /   A   R   X   S   G   P   O
1315000    >  \n
1315002

Estoy ejecutando AIX 5.3

Básicamente, o quiero que deje de agregar el extra \n, o encontrar una forma de eliminarlo.

jonnohudski
fuente
Solo una pregunta: ¿por qué está usando una nueva línea literal en su patrón de sustitución cuando podría haberlo usado s|...|&\n|también?
Joseph R.
1
@JosephR. \nen el lado derecho no es portátil.
Stéphane Chazelas
@StephaneChazelas Eso es raro. ¿Es una cosa CR vs CRLF?
Joseph R.
2
Un archivo que no termina en un carácter de nueva línea no es un archivo de texto, por lo que el comportamiento con las utilidades de texto no está especificado . Utilice perlu otra herramienta que pueda manejar datos binarios.
Stéphane Chazelas
44
@JosephR. No, \<LF>es la forma tradicional y POSIX de agregar un carácter LF. \nPor lo general, sustituiría un npersonaje en cualquier cosa que no sea GNU sed.
Stéphane Chazelas

Respuestas:

10

Debería considerarse afortunado de que AIX haya sedagregado los caracteres de nueva línea que faltan.

Un archivo no vacío que no termina en un carácter de nueva línea no es un archivo de texto (al menos según la definición POSIX de un archivo de texto) ya que un archivo de texto debe contener líneas y las líneas son un (no demasiado) largo) secuencia de caracteres terminados por un carácter de nueva línea, por lo que el comportamiento de las utilidades de texto como seden él no está especificado y en la práctica varía de implementación a implementación.

Algunas sedimplementaciones habrían descartado esos caracteres espurios después de la última línea.

AFAIK, los xmlarchivos están destinados a ser archivos de texto, por lo que eso significa que sedsolo lo arregló por usted.

Si necesita que ese archivo no termine en un carácter de nueva línea, puede usar perlu otras herramientas que puedan hacer frente a datos que no son de texto.

perl -pe 's|<LIST_G_STATEMENT>|$&\n|g'
Stéphane Chazelas
fuente
1
La nueva línea de terminación es útil, si espera canalizar su sedsalida a cualquier otra utilidad estándar de Unix. Honestamente, no me di cuenta de sedesto durante años , ya que las sustituciones de comandos de shell Bourne como$(sed 's/bas/replac/' <<<'basement') recortar furtivamente la nueva línea final, si hay una. Pero no son momentos en los que sin duda no lo quieren; por ejemplo , manipulando el texto del portapapeles X con sed. Para su información, GNU sed, si está disponible, no agrega una nueva línea de terminación si la usa pcon la -nopción, como se describe en esta respuesta SE .
TheDudeAbides
0

Aquí hay una manera de eliminar la nueva línea final de un archivo usando dd:

printf "" | dd  of='/path/to/file' seek=<filesize_in_bytes - 1> bs=1 count=1

Para probar si un archivo termina con una nueva línea, puede usar:

tail -c 1 /path/to/file | tr -dc '\n' | wc -c

Y para obtener el tamaño del archivo en bytes use:

wc -c < /path/to/file
chan
fuente
0

De acuerdo con este manual de AIX, IBM lo tailhace -rsiempre, lo que se ve muy bien. Mientras su archivo tenga menos de 20 KB, lo siguiente debería funcionar:

tail -r <file | dd bs=1 skip=1 | tail -r >file.new
mikeserv
fuente