bash - substitua o espaço por nova linha


70

Como posso substituir espaços por novas linhas em uma entrada como:

/path/to/file /path/to/file2 /path/to/file3 /path/to/file4 /path/to/file5 etc ...

Para obter o seguinte:

/path/to/file
/path/to/file2
/path/to/file3
/path/to/file4
/path/to/file5

Nota

Estou postando esta pergunta para ajudar outros usuários, não foi fácil encontrar uma resposta útil no UNIX SE até começar a digitar esta pergunta. Depois disso, encontrei o seguinte:

Pergunta relacionada

Como posso encontrar e substituir por uma nova linha?



ls / caminho / para / | xargs eco | sed 's / \ s \ + / \ n / g'
DP.

Respostas:



20

Nesse caso, eu usaria printf:

printf '%s\n' /path/to/file /path/to/file2 /path/to/file3 /path/to/file4 /path/to/file5

Se houver espaços dentro de um dos caminhos, é possível citar esse caminho de arquivo para impedir que ele seja dividido nos espaços:

printf '%s\n' /path/to/file '/path/to/file with spaces' /path/to/another/file

Transformar texto em geral, tré sua melhor aposta, conforme coberto em uma resposta existente.


11
Uma observação rápida do futuro: obrigado por postar esta solução, tem sido muito confiável para mim, em comparação com o uso de "eco".
Liesmith #

5

Supondo que você tenha uma sequência com espaços como separadores:

newline_separated=${space_separated// /$'\n'}

No entanto, você provavelmente está fazendo a pergunta errada. (Não necessariamente, por exemplo, isso pode aparecer em um makefile.) Uma lista de nomes de arquivos separados por espaço não funciona realmente: e se um dos nomes de arquivos contivesse espaços?

Se um programa receber nomes de arquivos como argumentos, não os junte a espaços. Use "$@"para acessá-los um por um. Embora echo "$@"imprima os argumentos com espaços no meio, isso se deve a echo: imprime seus argumentos com espaços como separadores. somecommand "$@"passa os nomes dos arquivos como argumentos separados para o comando Se você deseja imprimir os argumentos em linhas separadas, pode usar

printf '%s\n' "$@"

Se você possui nomes de arquivos separados por espaço e deseja colocá-los em uma matriz para trabalhar com eles, pode usar uma expansão de variável não citada para dividir o valor em caracteres IFS(você precisará desativar a expansão de curinga com set -f, caso contrário, glob os padrões serão expandidos no valor):

space_separated_list='/path/to/file1 /path/to/file2 /path/to/file3'
IFS=' '; set -f
eval "array=(\$space_separated_list)"
for x in "${array[@]}"; do 

Você pode encapsular isso em uma função que restaura a -fconfiguração e o valor de IFSquando é feito:

split_list () {
  local IFS=' ' flags='+f'
  if [[ $- = *f* ]]; then flags=; fi
  set -f
  eval "$1=($2)"
  set $flags
}
split_list array '/path/to/file1 /path/to/file2 /path/to/file3'
for x in "${array[@]}"; do 

Alterando a resposta correta para esta. Eu acho que é mais correto pesquisar como cheguei a uma lista separada por espaço e recuperar essas informações de outra maneira. Seria legal para alunos como eu se você comentar um pouco o seu snipnet, nos dizendo o que fazem coisas como a var IFS local ou a condição $ - = f . Esse tipo de coisa que uma pessoa que usa o bash algumas vezes não sabe.
laconbass

@laconbass Adicionei uma breve explicação. Olhe para cima set -fe IFSno manual do bash se você quiser todos os detalhes. Veja também unix.stackexchange.com/questions/16192/…
Gilles 'SO- stop

@ Guilles Essa breve explicação é suficiente para mim, e acho que será para muitas outras. Ty para seu tempo
laconbass 12/12/14

definição IFSlocalmente não terá efeito
Eliran Malka

@EliranMalka Não tenho idéia do que você quer dizer com isso. Se um script não se comportar da maneira que você pensa, você pode fazer uma pergunta aqui.
Gilles 'SO- stop be evil' -

4

Seja pragmático, use sed !!

sed 's/\s\+/\n/g' file

O texto acima diz para substituir um ou mais caracteres de espaço em branco (\ s +) por nova linha (\ n)

Isto é mais ou menos:

'substitute /one space or more/ for /newline/ globally'

11
substituir a mudança pelo substituto, é isso que realmente significa!
Rob

@ Rob obrigado, lembre-se de que você pode editar as respostas de outras pessoas.
MGP

11
Se você tiver vários espaços entre o texto, obterá linhas em branco. Você precisa adicionar um '+' após \ s para indicar que deseja combinar pelo menos um espaço, ao invés de exatamente um espaço. ie sed 's / \ s + / \ n / g'
DarkHeart

4

Como alternativa ao tr@laconbass, você também pode usar xargsneste caso:

echo "/path/to/file /path/to/file2 /path/to/file3 /path/to/file4  /path/to/file5"\
| xargs -n1

A vantagem é que ele funciona mesmo com vários espaços em branco, o que trnão funciona.


0

Aqui está como eu fiz isso:

echo "/path/to/file /path/to/file2 /path/to/file3 /path/to/file4 /path/to/file5" | sed 's/ /\
'/g

Observe o uso da tecla Enter após a barra invertida no sedcomando.


que prós e contras sedacabou tr?
laconbass

Seu nível de conforto :-) Eu acho que você pode fazer mais sed, pois é um editor, em vez de simplesmente traduzir caracteres.
unxnut

4
sedpode fazer muito mais, mas é um exagero para isso. tré a ferramenta certa para ESTE trabalho, mas o conhecimento sede as expressões regulares certamente serão úteis mais tarde!
Rob

0

Outra abordagem, assumindo que a linha esteja em uma variável chamada line:

for path in $line;do echo $path;done

Isso usa o fato de que o Bash divide seus argumentos em espaço em branco por padrão e que echoacrescenta uma nova linha à sua entrada por padrão.


Eu tentei isso no meu sistema ubuntu antes de postar esta pergunta e não consegui fazê-la funcionar.
laconbass

0
echo word1 word2 ... | sed -e 'y/ /\n/;P;D'

é outro método para transformar palavras separadas por espaço único em nova linha separada.


-1

O script a seguir é fácil de entender e fácil de usar.

cat filename | tr ' ' '\n' | tee filename

2
A essência da sua resposta ( tr) é a mesma da resposta aceita. Além de sua resposta ter os seguintes problemas: a) o comando não é recuado com 4 espaços (-> layout de remarcação) b) Seu uso de caté inútil (você pode substituí-lo por < filename tr ' ' '\n'). c) O nome do arquivo de saída é igual ao nome do arquivo de entrada. Com isso, você cria uma corrida de dados.
maxschlepzig 03/09/2015

11
além da análise correta de maxschlepzig, este não é um script, mas um monte de comandos conectados que têm um nome codificado (como o script esperaria ter um cabeçalho especificando o shell para usar e usar dois parâmetros para especificar entrada e saída). Além disso, 2 em cada 3 pessoas em minha casa não acham fácil entender. Talvez isso não seja representativo, mas lembre-se de que algo que você entende (ou, nesse caso, acha que entende) sempre parece fácil.
Anthon
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.