sed falha ao remover o caractere de nova linha

12

Estou usando sedhá algum tempo, mas aqui está uma peculiaridade com a qual me deparo, que não consigo resolver.

Deixe-me explicar meu problema com o caso real.


Cena # 1

printf "ls" | xclip -selection clipboard
echo "ls" | xclip -selection clipboard

No primeiro comando, canalizo a printfsaída para, xclippara que seja copiada para a área de transferência. Agora, printfao contrário de echonão insere uma nova linha no final por padrão. Portanto, se eu colar esse conteúdo no terminal, o lscomando copiado não será executado automaticamente.

No segundo, há uma nova linha no final, portanto, colar o conteúdo da área de transferência também resulta na execução do comando na área de transferência.

Isso é indesejável para mim. Então, eu queria remover a nova linha usando sed, mas ela falhou, conforme explicado na cena abaixo.

Cena # 2

echo "ls" | sed -r 's/\n//g' | xclip -selection clipboard

O conteúdo da área de transferência ainda contém nova linha. Quando colo no terminal, o comando é executado automaticamente.

Eu também tentei remover o caractere de retorno de carro \r. Mas nada. Parece que estou perdendo algo muito crucial / básico aqui.

shivams
fonte

Respostas:

16

seddelimita as \nlinhas de ew - elas são sempre removidas na entrada e reinseridas na saída. Há não um \ncaráter ewline em um sedespaço de padrões que não ocorreu como resultado de uma edição que você fez. Nota: com exceção de GNU sed's -zmodo de ...

Basta usar tr:

echo ls | tr -d \\n | xclip -selection clipboard

Ou, melhor ainda, esqueça sedcompletamente:

printf ls | xclip -selection clipboard
mikeserv
fonte
Isso removerá todas as novas linhas, geralmente não desejáveis ​​no generate-text | xclipcaso. Esta resposta remove apenas a última nova linha.
Tom Hale
7

Muitas ferramentas de processamento de texto, incluindo sed, operam no conteúdo da linha, excluindo o caractere de nova linha. A primeira coisa que o sed faz ao processar uma linha é retirar a nova linha no final, depois executa os comandos no script e adiciona uma nova linha final ao imprimir. Portanto, você não poderá remover a nova linha com o sed.

Para remover todas as novas linhas, você pode usar tr:

echo "ls" | tr -d '\n' | xclip

Gilles 'SO- parar de ser mau'
fonte
4

Você pode substituir as novas linhas no sed passando a opção -z .

sed -z 's/\n/ /g'

Página de manual do Sed:

-z, --null-data separa linhas por caracteres NUL

JSON C11
fonte
Isso removerá todas as novas linhas, o que geralmente não é desejado no | xclipcaso.
Tom Hale
2

Se você está apenas colocando comandos na área de transferência

echo -n "ls " | xclip -selection clipboard

Se você precisar fazer transformações mais complexas,

echo "ls  " | perl -pe 's/\n//' | xclip -selection clipboard
JJoao
fonte
Hmm. Solução suave. Eu acho que talvez seja hora de passar para perl ou python para regex.
shivams
3
@shivams - perle pythonsão muito mais lentos do que sedquando usados ​​corretamente. Aprender a usá-lo corretamente é a chave.
precisa saber é o seguinte
@mikeserv - eu concordo; especial para oneliner sed é maravilhoso. Se as transformações se tornarem mais complexas, prefiro perl / python / gawk.
JJoao
1
@JJoa: Sua preferência é o seu próprio, mas sedpode fazer muito mais do que pega apenas seus one-liners, e provavelmente pode fazê-lo mais rápido do que qualquer uma dessas outras ferramentas que você menciona.
mikeserv
1
@ mikeserv - mais uma vez, eu concordo com você. Há um ano, eu tinha um sistema de tradução EN-PT escrito em sed (20000 s /.../.../), gerado por sed! E funcionou! Mais tarde, tornou-se Perl, com matrizes, hashes, funções, pacotes e CPAN.
precisa saber é
1

Para remover apenas a última nova linha , passe por:

sed -z '$ s/\n$//'

sednão adicionará um \0ao final do fluxo se o delimitador estiver definido como NULvia -z, enquanto que para criar um arquivo de texto POSIX (definido para terminar em a \n), ele sempre produzirá um final \nsem -z.

Por exemplo:

$ { echo foo; echo bar; } | sed -z '$ s/\n$//'; echo tender
foo
bartender

E para provar que não foi NULadicionado:

$ { echo foo; echo bar; } | sed -z '$ s/\n$//' | xxd
00000000: 666f 6f0a 6261 72                        foo.bar

Para remover várias linhas novas à direita , passe por:

sed -Ez '$ s/\n+$//'
Tom Hale
fonte