Como aparo os espaços em branco à esquerda e à direita de cada linha de alguma saída?

155

Gostaria de remover todos os espaços e guias à esquerda e à direita de cada linha de uma saída.

Existe uma ferramenta simples como trimeu poderia canalizar minha saída?

Arquivo de exemplo:

test space at back 
 test space at front
TAB at end  
    TAB at front
sequence of some    space in the middle
some empty lines with differing TABS and spaces:





 test space at both ends 
rubo77
fonte
1
Para quem procura aqui uma solução para remover novas linhas, esse é um problema diferente. Por definição, uma nova linha cria uma nova linha de texto. Portanto, uma linha de texto não pode conter uma nova linha. A pergunta que você deseja fazer é como remover uma nova linha do início ou do final de uma string: stackoverflow.com/questions/369758 ou como remover linhas em branco ou linhas que são apenas espaços em branco: serverfault.com/questions/252921
Tony

Respostas:

200
awk '{$1=$1;print}'

ou mais curto:

awk '{$1=$1};1'

Cortaria os caracteres à esquerda e à esquerda ou os caracteres de tabulação 1 e também comprimiria seqüências de tabs e espaços em um único espaço.

Isso funciona porque quando você atribui algo a um dos campos , awkreconstrói todo o registro (conforme impresso por print) juntando todos os campos ( $1, ..., $NF) com OFS(espaço por padrão).

1 (e possivelmente outros caracteres em branco, dependendo da localidade e da awkimplementação)

Stéphane Chazelas
fonte
2
O ponto e vírgula no segundo exemplo é supérfluo. Pode usar:awk '{$1=$1}1'
Brian
8
@ Brian, não, o ;é exigido na sintaxe awk padrão
Stéphane Chazelas
Interessante ... Nenhum ponto-e-vírgula é suportado pelo gawk, mawk e pelo awk do OS X. (Pelo menos para as minhas versões (1.2, 4.1.1 e 20070501, respectivamente))
Brian
1
A única coisa que eu não gosto nessa abordagem é que você perde espaços repetidos na linha. Por exemplo,echo -e 'foo \t bar' | awk '{$1=$1};1'
user.friendly
2
echo ' hello ' | xargs
JREAM #
44

O comando pode ser condensado assim, se você estiver usando o GNU sed:

$ sed 's/^[ \t]*//;s/[ \t]*$//' < file

Exemplo

Aqui está o comando acima em ação.

$ echo -e " \t   blahblah  \t  " | sed 's/^[ \t]*//;s/[ \t]*$//'
blahblah

Você pode hexdumpconfirmar se o sedcomando está removendo os caracteres desejados corretamente.

$ echo -e " \t   blahblah  \t  " | sed 's/^[ \t]*//;s/[ \t]*$//' | hexdump -C
00000000  62 6c 61 68 62 6c 61 68  0a                       |blahblah.|
00000009

Classes de caracteres

Você também pode usar nomes de classes de caracteres em vez de listar literalmente os conjuntos como este [ \t]:

$ sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//' < file

Exemplo

$ echo -e " \t   blahblah  \t  " | sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//'

A maioria das ferramentas GNU que usam expressões regulares (regex) suportam essas classes.

 [[:alnum:]]  - [A-Za-z0-9]     Alphanumeric characters
 [[:alpha:]]  - [A-Za-z]        Alphabetic characters
 [[:blank:]]  - [ \x09]         Space or tab characters only
 [[:cntrl:]]  - [\x00-\x19\x7F] Control characters
 [[:digit:]]  - [0-9]           Numeric characters
 [[:graph:]]  - [!-~]           Printable and visible characters
 [[:lower:]]  - [a-z]           Lower-case alphabetic characters
 [[:print:]]  - [ -~]           Printable (non-Control) characters
 [[:punct:]]  - [!-/:-@[-`{-~]  Punctuation characters
 [[:space:]]  - [ \t\v\f]       All whitespace chars
 [[:upper:]]  - [A-Z]           Upper-case alphabetic characters
 [[:xdigit:]] - [0-9a-fA-F]     Hexadecimal digit characters

Usar esses conjuntos em vez de conjuntos literais sempre parece um desperdício de espaço, mas se você estiver preocupado com seu código ser portátil ou precisar lidar com conjuntos de caracteres alternativos (pense internacional), provavelmente usará os nomes das classes em vez de.

Referências

slm
fonte
Observe que isso [[:space:]]não é equivalente ao [ \t]caso geral (unicode, etc). [[:space:]]provavelmente será muito mais lento (pois há muito mais tipos de espaços em branco no unicode do que just ' 'e '\t'). A mesma coisa para todos os outros.
Olivier Dulac
sed 's/^[ \t]*//'não é portátil. Na verdade, o POSIX ainda exige que remova uma sequência de espaço, barra invertida ou tcaracteres, e é isso que o GNU sedtambém faz quando POSIXLY_CORRECTestá no ambiente.
Stéphane Chazelas
E se eu quiser aparar caracteres de novas linhas? '\ n \ n text \ n \ n'
Eugene Biryukov
Eu gosto da solução sed devido à falta de outros efeitos colaterais, como na solução awk. A primeira variação não funciona quando eu tentei no bash no OSX jsut agora, mas a versão da classe de personagem funciona:sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//'
Tony
@EugeneBiryukov ver meu comentário no post original
Tony
23

Conforme sugerido por Stéphane Chazelas na resposta aceita, agora você pode
criar um script /usr/local/bin/trim:

#!/bin/bash
awk '{$1=$1};1'

e conceda direitos executáveis ​​a esse arquivo:

chmod +x /usr/local/bin/trim

Agora você pode passar todas as saídas para, trimpor exemplo:

cat file | trim

(para os comentários abaixo: eu usei isso antes: o while read i; do echo "$i"; done
que também funciona bem, mas tem menos desempenho)

rubo77
fonte
1
Boa sorte se o seu arquivo for grande e / ou contiver barras invertidas.
don_crissti
1
@don_crissti: você poderia comentar um pouco mais ?, qual solução seria mais adequada para arquivos grandes e como eu poderia modificar minha solução se o arquivo contenha barras invertidas?
rubo77
3
Você terá que usar while read -r linepara preservar barras invertidas e mesmo assim ... . Quanto aos enormes arquivos / velocidade, realmente, você escolheu a pior solução. Eu não acho que haja algo pior por aí. Veja as respostas em Por que está usando um loop de shell para processar práticas inadequadas de texto? incluindo meu comentário sobre a última resposta em que adicionei um link a um benchmark de velocidade. As sedrespostas aqui são perfeitamente bem IMO e muito melhor que read.
don_crissti
@don_crissti ... e / ou possui linhas começando com -e seguidas por combinações de 1 ou mais caracteres e, E ou n e / ou contém caracteres NUL. Além disso, uma linha não terminada após a última nova linha será ignorada.
Stéphane Chazelas
1
Você também pode adicionar um alias em / etc / profile (ou seu ~ / .bashrc ou ~ / .zshrc etc ...) alias trim = "awk '{\ $ 1 = \ $ 1}; 1'"
Jeff Clayton
22

xargs sem argumentos fazem isso.

Exemplo:

trimmed_string=$(echo "no_trimmed_string" | xargs) 
Newton_Jose
fonte
1
Isso também contrata vários espaços dentro de uma linha, que não foi solicitado na pergunta
roaima
1
@roaima - true, mas a resposta aceita também comprime espaços (o que não foi solicitado na pergunta). Acho que o verdadeiro problema aqui é que xargsfalhará na entrega se a entrada contiver barras invertidas e aspas simples.
don_crissti
@don_crissti que não significa que a resposta aceita responda corretamente à pergunta, conforme solicitado. Mas, neste caso, aqui não foi sinalizado como uma advertência, enquanto na resposta aceita foi. Espero destacar o fato, caso seja relevante para um futuro leitor.
roaima 9/09/2015
Ele também quebra entre aspas simples, aspas duplas, caracteres de barra invertida. Também executa uma ou mais echoinvocações. Algumas implementações de eco também processam opções e / ou barras invertidas ... Isso também funciona apenas para entrada de linha única.
Stéphane Chazelas
17
sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'

Se você está lendo uma linha em uma variável shell, readisso já é feito, a menos que seja instruído de outra forma .

Gilles
fonte
1
+1 para read. Então, se você tubo para enquanto lê-lo funciona:cat file | while read i; do echo $i; done
rubo77
1
@rubo, exceto que, no seu exemplo, a variável não citada também é reprocessada pelo shell. Use echo "$i"para ver o verdadeiro efeito doread
roaima 9/09/15
13

Se você armazenar linhas como variáveis, poderá usar o bash para fazer o trabalho:

remova o espaço em branco à esquerda de uma sequência:

shopt -s extglob
echo ${text##+([[:space:]])}

remova o espaço em branco à direita de uma string:

shopt -s extglob
echo ${text%%+([[:space:]])}

remova todo o espaço em branco de uma string:

echo ${text//[[:space:]]}
Łukasz Rajchel
fonte
Remover todo o espaço em branco de uma sequência de caracteres não é o mesmo que remover os espaços iniciais e finais (como em questão).
catpnosis
De longe a melhor solução - requer apenas bash builtins e nenhum garfo de processo externo.
user259412
2
Agradável. Os scripts executam MUITO mais rápido se não forem necessários programas externos (como awk ou sed). Isso funciona também com as versões "modernas" (93u +) do ksh.
user1683793
9

Para remover todos os espaços iniciais e finais de uma determinada linha, graças a uma ferramenta 'encanada', posso identificar três maneiras diferentes que não são completamente equivalentes. Essas diferenças dizem respeito aos espaços entre as palavras da linha de entrada. Dependendo do comportamento esperado, você fará sua escolha.

Exemplos

Para explicar as diferenças, vamos considerar esta linha de entrada fictícia:

"   \t  A   \tB\tC   \t  "

tr

$ echo -e "   \t  A   \tB\tC   \t  " | tr -d "[:blank:]"
ABC

tré realmente um comando simples. Nesse caso, ele exclui qualquer caractere de espaço ou tabulação.

awk

$ echo -e "   \t  A   \tB\tC   \t  " | awk '{$1=$1};1'
A B C

awk exclui os espaços iniciais e finais e pressiona em um único espaço todos os espaços entre as palavras.

sed

$ echo -e "   \t  A   \tB\tC   \t  " | sed 's/^[ \t]*//;s/[ \t]*$//'
A       B   C

Nesse caso, sedexclui os espaços iniciais e finais sem tocar em nenhum espaço entre as palavras.

Observação:

No caso de uma palavra por linha, trfaz o trabalho.

frozar
fonte
Nada disso guarnições arrastando / novas linhas principais embora
highmaintenance
+1 para obter uma lista de soluções com saída (às vezes inesperada).
Tony
@ user61382 é tarde demais, mas veja meu comentário na postagem original.
Tony
@highmaintenance: use [:space:], em vez de [: blank:], para o comando tr, como :, ... | tr -d [:space:]para remover novas linhas também. (ver: man tr)
tron5
6

O sed é uma ótima ferramenta para isso:

                        # substitute ("s/")
sed 's/^[[:blank:]]*//; # parts of lines that start ("^")  with a space/tab 
     s/[[:blank:]]*$//' # or end ("$") with a space/tab
                        # with nothing (/)

Você pode usá-lo para o seu caso, seja no texto, por exemplo,

<file sed -e 's/^[[...

ou agindo de forma 'inline' se você sedé o GNU:

sed -i 's/...' file

mas alterar a fonte dessa maneira é "perigoso", pois pode ser irrecuperável quando não funciona direito (ou mesmo quando funciona!), portanto faça o backup primeiro (ou o uso -i.bakque também tem o benefício de ser portátil para alguns BSDs sed) !

Michael Durrant
fonte
2

comando translate funcionaria

cat file | tr -d [:blank:]
Srinagesh
fonte
4
Este comando não está correto, pois remove todos os espaços do arquivo, não apenas os espaços em branco iniciais / finais.
Brian Redbeard 28/09
@BrianRedbeard Você está correto. Essa ainda é uma resposta útil para uma cadeia monolítica, sem espaços.
Anthony Rutledge
0

Se a string que está tentando aparar for curta e contínua / contígua, pode-se simplesmente passá-la como parâmetro para qualquer função bash:

    trim(){
        echo $@
    }

    a="     some random string   "

    echo ">>`trim $a`<<"
Output
>>some random string<<
Subrata Das
fonte