2010-05-26 15 views
9

Tengo un archivo de texto ("input.txt") del formato:UNIX: Reemplazar nueva línea w/Colón, La preservación de nueva línea Antes de EOF

A<LF> 
B<LF> 
C<LF> 
D<LF> 
X<LF> 
Y<LF> 
Z<LF> 
<EOF> 

cual necesito volver a formatear a:

A:B:C:D:X:Y:Z<LF> 
<EOF> 

Sé que puedes hacer esto con 'sed'. Hay mil millones de visitas de Google para hacer esto con 'sed'. Pero estoy tratando de enfatizar la legibilidad, la simplicidad y el uso de la herramienta correcta para el trabajo correcto. 'sed' es un editor de línea que consume y oculta nuevas líneas. ¡Probablemente no sea la herramienta adecuada para este trabajo!

Creo que la herramienta correcta para este trabajo sería 'tr'. Puedo reemplazar todos los saltos de línea con dos puntos con el comando:

cat INPUT.txt | tr '\n' ':' 

Hay 99% de mi trabajo realizado. Tengo un problema, ahora, sin embargo. Al reemplazar todas las líneas nuevas con dos puntos, no solo obtengo dos puntos extraños al final de la secuencia, sino que también pierdo el retorno de carro al final de la entrada. Se ve así:

A:B:C:D:X:Y:Z:<EOF> 

Ahora, necesito eliminar los dos puntos del final de la entrada. Sin embargo, si intento pasar esta entrada procesada a través de 'sed' para eliminar el colon final (que ahora, creo, sería un uso apropiado de 'sed'), me encuentro con un segundo problema. ¡La entrada ya no está terminada por una nueva línea! 'sed' falla rotundamente, para todos los comandos, ¡porque nunca encuentra el final de la primera línea de entrada!

Parece que agregar una nueva línea al final de una entrada es una tarea muy, muy común, y considerando que yo mismo estaba tentado de escribir un programa para hacerlo en C (que tomaría aproximadamente ocho líneas de código)), No puedo imaginar que no haya una manera muy simple de hacerlo con las herramientas que ya están disponibles para usted en el kernel de Linux.

Respuesta

13

Esto debería hacer el trabajo (cat y echo son innecesarios):

tr '\n' ':' < INPUT.TXT | sed 's/:$/\n/' 

Usando sólo sed:

sed -n ':a; $ ! {N;ba}; s/\n/:/g;p' INPUT.TXT 

Bash sin ningún tipo de factores externos:

string=($(<INPUT.TXT)) 
string=${string[@]/%/:} 
string=${string//: /:} 
string=${string%*:} 

Uso de un bucle en sh:

colon='' 
while read -r line 
do 
    string=$string$colon$line 
    colon=':' 
done < INPUT.TXT 

Utilizando AWK:

awk '{a=a colon $0; colon=":"} END {print a}' INPUT.TXT 

O:

awk '{printf colon $0; colon=":"} END {printf "\n" }' INPUT.TXT 

Editar:

Ésta es otra manera en Bash pura:

string=($(<INPUT.TXT)) 
saveIFS=$IFS 
IFS=':' 
newstring="${string[*]}" 
IFS=$saveIFS 

Edición 2:

Aquí hay otra manera de la que hace uso echo:

echo "$(tr '\n' ':' < INPUT.TXT | head -c -1)" 
+0

Al principio estaba desconcertada de por qué publicaría como solución lo que dije que no funcionaba, así que lo probé en otra máquina. Me di cuenta de que el servidor Sun en el que necesitaba la solución no usaba GNU 'sed'. La versión de 'sed' en el servidor falla cuando la entrada no tiene una nueva línea de terminación, por lo tanto, como se indica, ¿por qué utilicé 'eco'? ((El servidor es un dispositivo de misión crítica en el trabajo que nunca ha fallado, y por lo tanto, nunca se ha reiniciado, ni mucho menos actualizado, en años. Bienvenido a mi vida)) La solución de bucle de shell es impresionante, aunque . – Maarx

+0

/bin/sed on Sun ... ick. ¿Qué tal/usr/xpg4/bin/sed? –

1

Aquí hay otra solución: (asume un conjunto de caracteres, donde ':' es octal 72, por ejemplo, ascii)

 
perl -l72 -pe '$\="\n" if eof' INPUT.TXT 
2

Pregunta anterior, pero

paste -sd: INPUT.txt