Como remover uma nova linha de uma string no Bash

110

Eu tenho a seguinte variável.

echo "|$COMMAND|"

que retorna

|
REBOOT|

Como posso remover a primeira nova linha?

Matt Leyland
fonte
7
Por que isso está marcado como um idiota? Esta pergunta é sobre como remover um retorno de carro. A suposta pergunta duplicada à qual ele se vincula é sobre a remoção de espaços em branco, e apenas acidentalmente menciona retornos de carro.
Michael Scheper,
1
@MichaelScheper concordou e reabriu.
fedorqui 'SO pare de prejudicar'
A terminologia aqui é estranha. O caractere de terminação de linha Unix \n(hex 0x0A) é chamado de feed de mentira (LF); é diferente do retorno de carro do caractere (CR) \r(hex 0x0D) que é usado no Windows e em muitos protocolos de rede como o primeiro byte na sequência de fim de linha de dois bytes CR LF.
tripleee

Respostas:

114

Debaixo , existem alguns bashismos:

O trcomando pode ser substituído por // bashism :

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

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

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

Consulte Expansão de parâmetro e CITAÇÃO na página de manual do bash:

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

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

Mais distante...

Conforme solicitado por @AlexJordan, isso suprimirá todos os caracteres especificados. E se $COMMANDcontiverem espaços ...

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|

Em breve:

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

Nota: tem a extglobopção de estar habilitado ( shopt -s extglob) para usar a *(...)sintaxe.

F. Hauri
fonte
1
Esta é a maneira de remover alimentações de linha de uma variável no BASH. Outras respostas estão invocando desnecessariamente um processo TR extra. BTW, tem o benefício adicional de remover espaços finais!
ingyhere
1
Observe que também remove os espaços internos de uma string ... COMMAND="RE BOOT"; echo "|${COMMAND//[$'\t\r\n ']}|"retorna|REBOOT|
Alex Jordan
2
@AlexJordan Sim, é um recurso desejado : você pode limpar o espaço depois \npara evitar que: COMMAND="RE BOOT"; echo "|${COMMAND//[$'\t\r\n']}|"retornará |RE BOOT|.
F. Hauri
2
Como o padrão está funcionando ${COMMAND//[$'\t\r\n']}? Achei ${COMMAND//[\t\r\n]}que simplesmente funcionaria, mas não funcionou. Para que serve o $símbolo e também as aspas simples?
haridsv
1
Com relação à sintaxe $ '', essa é a cotação ANSI C (mencionada na resposta de wjordans).
chuckx
81
echo "|$COMMAND|"|tr '\n' ' '

irá substituir a nova linha (em POSIX / Unix não é um retorno de carro) por um espaço.

Para ser honesto, eu pensaria em mudar do bash para algo mais lógico. Ou evitando gerar esses dados malformados em primeiro lugar.

Hmmm, isso parece que também pode ser uma falha de segurança horrível, dependendo de onde os dados estão vindo.

Robin Green
fonte
A data vem de uma solicitação curl que está no mesmo servidor. Como eu faria para colocar isso em uma nova var? newvar = $ (echo "| $ COMMAND |" | tr '\ n' '')
Matt Leyland
2
Sim. Mas por favor me diga que você não está permitindo que pessoas arbitrárias reiniciem seu servidor remotamente sem uma senha ...
Robin Green
31
Por que você não usou tr -d '\n'para soltar em vez de substituir por um espaço
F. Hauri
3
Por favor, chicoteie canos inúteis! Use em tr '\n' ' ' <<< "|$COMMAND|"vez deecho ... | ...
F. Hauri
12
@ F.Hauri: ou tr's inúteis:"|${COMMAND//$'\n'}|"
rici
75

Limpe sua variável removendo todos os retornos de carro:

COMMAND=$(echo $COMMAND|tr -d '\n')
Maxime Chéramy
fonte
22
Isso não tira os feeds de linha? Não deveria ser tr -d '\r'?
Izzy
3
Ecoar uma variável não comentada remove todos os caracteres IFS (nova linha, espaço, tab por padrão). Portanto, se for fazer isso, você deve estar ciente de que todos os caracteres IFS são eliminados e você não precisa do tr. Simplesmente COMMAND=$(echo $COMMAND)dará um efeito semelhante. Que é, presumivelmente, a criação do diabo, pois invoca um novo processo, mas ainda é muito curto e agradável para os olhos humanos e se você tiver um ou dois segundos sobrando em sua vida, você pode estar disposto a aceitar o golpe :-).
Mike S
Eu atualizei a pergunta para dizer "alimentação de linha", já que seu exemplo mostrou que era uma alimentação de linha, não um retorno de carro. Esta resposta ainda está correta, mas talvez deva ser atualizada para dizer "alimentação de linha" em vez de "retorno de carro"?
Benjamin W.
8

Usando bash:

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

(Observe que o caractere de controle nesta questão é uma 'nova linha' ( \n), não um retorno de carro ( \r); o último teria a saída REBOOT|em uma única linha.)

Explicação

Usa a expansão de parâmetro do Bash Shell${parameter/pattern/string} :

O padrão é expandido para produzir um padrão exatamente como na expansão de nome de arquivo. O parâmetro é expandido e a correspondência mais longa do padrão com seu valor é substituída por string . [...] Se a string for nula, as correspondências do padrão são excluídas e o / seguinte padrão pode ser omitido.

Também usa a construção de $'' cotação ANSI-C para especificar uma nova linha como $'\n'. Usar uma nova linha diretamente também funcionaria, embora menos bonito:

echo "|${COMMAND/
}|"

Exemplo completo

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

Ou, usando novas linhas:

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

O que funcionou para mim foi echo $testVar | tr "\n" " "

Onde testVar continha minha variável / saída de script

Prachi
fonte
4

Adicionando resposta para mostrar um exemplo de remoção de vários caracteres, incluindo \ r usando tr e usando sed. E ilustrando usando hexdump.

No meu caso, descobri que um comando terminando com awk print do último item |awk '{print $2}'da linha incluía um retorno de carro \ r, bem como aspas.

Eu costumava sed 's/["\n\r]//g'retirar tanto o retorno de carro quanto as citações.

Eu também poderia ter usado tr -d '"\r\n'.

É interessante notar que sed -zé necessário se alguém deseja remover \ n caracteres de feed de linha.

$ 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   |

E isso é relevante: O que são retorno de carro, avanço de linha e avanço de formulário?

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

Você pode simplesmente usar echo -n "|$COMMAND|".

Paulo
fonte
2

Se você estiver usando o bash com a opção extglob ativada, poderá remover apenas o espaço em branco à direita:

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

Isso resulta em:

|
RE BOOT|

Ou substitua %% por ## para substituir apenas o espaço em branco inicial.

zeroimpl
fonte
1
Isso funcionou perfeitamente com alguns resultados estranhos que recebi de um comando docker. Muito obrigado!
develCuy