Cómo eliminar una nueva línea de una cadena en Bash

110

Tengo la siguiente variable.

echo "|$COMMAND|"

que regresa

|
REBOOT|

¿Cómo puedo eliminar esa primera nueva línea?

Matt Leyland
fuente
7
¿Por qué esto está marcado como un engaño? Esta pregunta trata sobre la eliminación de un retorno de carro. La supuesta pregunta duplicada a la que se vincula es sobre la eliminación de espacios en blanco, y solo menciona de manera incidental los retornos de carro.
Michael Scheper
1
@MichaelScheper estuvo de acuerdo y reabrió.
fedorqui 'SO deja de dañar'
La terminología aquí es extraña. El carácter de terminación de línea de Unix \n(hexadecimal 0x0A) se llama alimentación de mentira (LF); es distinto del retorno de carro de caracteres (CR) \r(hex 0x0D) que se utiliza en Windows y en muchos protocolos de red como el primer byte en la secuencia de final de línea de dos bytes CR LF.
tripleee

Respuestas:

114

Debajo , hay algunos bashismos:

El trcomando podría ser reemplazado por // bashism :

COMMAND=$'\nREBOOT\r   \n'
echo "|${COMMAND}|"
|
   OOT
|

echo "|${COMMAND//[$'\t\r\n']}|"
|REBOOT   |

echo "|${COMMAND//[$'\t\r\n ']}|"
|REBOOT|

Consulte Expansión de parámetros y COTIZACIÓN en la página de manual de bash:

man -Pless\ +/\/pattern bash
man -Pless\ +/\\\'string\\\' bash

man -Pless\ +/^\\\ *Parameter\\\ Exp bash
man -Pless\ +/^\\\ *QUOTING bash

Más lejos...

Como lo pidió @AlexJordan, esto suprimirá todos los caracteres especificados. Entonces, ¿ $COMMANDqué pasa si contienen espacios ...

COMMAND=$'         \n        RE BOOT      \r           \n'
echo "|$COMMAND|"
|
           BOOT      
|

CLEANED=${COMMAND//[$'\t\r\n']}
echo "|$CLEANED|"
|                 RE BOOT                 |

shopt -q extglob || { echo "Set shell option 'extglob' on.";shopt -s extglob;}

CLEANED=${CLEANED%%*( )}
echo "|$CLEANED|"
|                 RE BOOT|

CLEANED=${CLEANED##*( )}
echo "|$CLEANED|"
|RE BOOT|

Dentro de poco:

COMMAND=$'         \n        RE BOOT      \r           \n'
CLEANED=${COMMAND//[$'\t\r\n']} && CLEANED=${CLEANED%%*( )}
echo "|${CLEANED##*( )}|"
|RE BOOT|

Nota: tiene la extglobopción de estar habilitado ( shopt -s extglob) para usar la *(...)sintaxis.

F. Hauri
fuente
1
Esta es la forma de eliminar los avances de línea de una variable en BASH. Otras respuestas invocan innecesariamente un proceso de TR adicional. Por cierto, tiene el beneficio adicional de eliminar los espacios finales.
ingyhere
1
Tenga en cuenta que también elimina los espacios internos de una cadena ... COMMAND="RE BOOT"; echo "|${COMMAND//[$'\t\r\n ']}|"devuelve|REBOOT|
Alex Jordan
2
@AlexJordan Sí, es una característica deseada : puedes limpiar el espacio después \npara evitar que esto COMMAND="RE BOOT"; echo "|${COMMAND//[$'\t\r\n']}|"vuelva |RE BOOT|.
F. Hauri
2
¿Cómo está funcionando el patrón ${COMMAND//[$'\t\r\n']}? Pensé ${COMMAND//[\t\r\n]}que simplemente funcionaría, pero no fue así. ¿Para qué es el $símbolo y las comillas simples también?
haridsv
1
Con respecto a la sintaxis $ '', esa es la cita de ANSI C (mencionada en la respuesta de wjordans).
chuckx
81
echo "|$COMMAND|"|tr '\n' ' '

reemplazará la nueva línea (en POSIX / Unix no es un retorno de carro) con un espacio.

Sin embargo, para ser honesto, pensaría en cambiarme de bash a algo más sano. O evitar generar estos datos mal formados en primer lugar.

Hmmm, esto parece que también podría ser un agujero de seguridad horrible, dependiendo de dónde provengan los datos.

Robin Green
fuente
La fecha proviene de una solicitud curl que está en el mismo servidor, ¿cómo haría para poner eso en una nueva var? newvar = $ (echo "| $ COMMAND |" | tr '\ n' '')
Matt Leyland
2
Si. Pero por favor dígame que no está permitiendo que personas arbitrarias reinicien su servidor de forma remota sin una contraseña ...
Robin Green
31
¿Por qué no lo usó tr -d '\n'para soltar en lugar de reemplazar por un espacio
F.Hauri
3
¡Por favor, limpie las tuberías inútiles! Usar en tr '\n' ' ' <<< "|$COMMAND|"lugar deecho ... | ...
F.Hauri
12
@ F.Hauri: o tr's inútiles:"|${COMMAND//$'\n'}|"
rici
75

Limpia tu variable eliminando todos los retornos de carro:

COMMAND=$(echo $COMMAND|tr -d '\n')
Maxime Chéramy
fuente
22
¿Eso no elimina los avances de línea? ¿No debería ser tr -d '\r'en su lugar?
Izzy
3
Hacer eco de una variable no comentada elimina todos los caracteres IFS (nueva línea, espacio, tabulación por defecto). Entonces, si va a hacer esto, debe tener en cuenta que todos los caracteres IFS se eliminan y no necesita el tr. Simplemente COMMAND=$(echo $COMMAND)dará un efecto similar. Lo cual es, presumiblemente, el engendro del diablo, ya que invoca un nuevo proceso, pero sigue siendo bastante corto y dulce para los ojos del humano y si tiene uno o dos segundos de sobra en su vida, puede estar dispuesto a recibir el golpe :-).
Mike S
Actualicé la pregunta para que diga "salto de línea", ya que su ejemplo mostró que era un salto de línea, no un retorno de carro. Esta respuesta aún es correcta, pero tal vez debería actualizarse para decir "salto de línea" en lugar de "retorno de carro".
Benjamin W.
8

Usando bash:

echo "|${COMMAND/$'\n'}|"

(Tenga en cuenta que el carácter de control en esta pregunta es una 'nueva línea' ( \n), no un retorno de carro ( \r); este último tendría salida REBOOT|en una sola línea).

Explicación

Utiliza la expansión de parámetros de Bash Shell${parameter/pattern/string} :

El patrón se expande para producir un patrón como en la expansión de nombre de archivo. El parámetro se expande y la coincidencia más larga del patrón con su valor se reemplaza con una cadena . [...] Si la cadena es nula, coincidencias de patrón se eliminan y / siguiente patrón se puede omitir.

También utiliza la construcción de $'' comillas ANSI-C para especificar una nueva línea como $'\n'. Usar una nueva línea directamente también funcionaría, aunque menos bonito:

echo "|${COMMAND/
}|"

Ejemplo completo

#!/bin/bash
COMMAND="$'\n'REBOOT"
echo "|${COMMAND/$'\n'}|"
# Outputs |REBOOT|

O, usando nuevas líneas:

#!/bin/bash
COMMAND="
REBOOT"
echo "|${COMMAND/
}|"
# Outputs |REBOOT|
wjordania
fuente
6

Lo que funcionó para mí fue echo $testVar | tr "\n" " "

Donde testVar contenía mi variable / script-output

Prachi
fuente
4

Agregar una respuesta para mostrar un ejemplo de cómo eliminar varios caracteres, incluido \ r usando tr y usando sed. E ilustrando usando hexdump.

En mi caso, encontré que un comando que termina con awk print del último elemento |awk '{print $2}' de la línea incluía un retorno de carro \ r y comillas.

solía sed 's/["\n\r]//g' eliminar tanto el retorno de carro como las comillas.

También podría haber usado tr -d '"\r\n' .

Es interesante notar que sed -zes necesario si se desea eliminar \ n caracteres de avance de línea.

$ COMMAND=$'\n"REBOOT"\r   \n'

$ echo "$COMMAND" |hexdump -C
00000000  0a 22 52 45 42 4f 4f 54  22 0d 20 20 20 0a 0a     |."REBOOT".   ..|

$ echo "$COMMAND" |tr -d '"\r\n' |hexdump -C
00000000  52 45 42 4f 4f 54 20 20  20                       |REBOOT   |

$ echo "$COMMAND" |sed 's/["\n\r]//g' |hexdump -C
00000000  0a 52 45 42 4f 4f 54 20  20 20 0a 0a              |.REBOOT   ..|

$ echo "$COMMAND" |sed -z 's/["\n\r]//g' |hexdump -C
00000000  52 45 42 4f 4f 54 20 20  20                       |REBOOT   |

Y esto es relevante: ¿Qué son el retorno de carro, el avance de línea y el avance de formulario?

  • CR == \ r == 0x0d
  • LF == \ n == 0x0a
gaoithe
fuente
3

Simplemente puede usar echo -n "|$COMMAND|".

Paulo
fuente
2

Si está utilizando bash con la opción extglob habilitada, puede eliminar solo el espacio en blanco final a través de:

shopt -s extglob
COMMAND=$'\nRE BOOT\r   \n'
echo "|${COMMAND%%*([$'\t\r\n '])}|"

Esto produce:

|
RE BOOT|

O reemplace %% con ## para reemplazar solo el espacio en blanco inicial.

zeroimpl
fuente
1
Esto funcionó a las mil maravillas con un resultado extraño que obtuve de un comando de la ventana acoplable. ¡Muchas gracias!
develCuy