Você precisa fazer uma citação dupla (e você deve variáveis de aspas duplas maioria dos casos):
echo "$LS"
Mas não use echo para imprimir conteúdo de variáveis, usando printf :
printf '%s\n' "$LS"
Estou tentando armazenar várias linhas em uma variável bash, mas parece que não funciona.
Por exemplo, se eu listar /bin
um arquivo por linha e armazená-lo em $LS
, então passo $LS
como stdin para wc
, ele sempre retorna 1:
$ ls -1 /bin | wc -l
134
$ LS=$(ls -1 /bin); wc -l <<< $LS
1
Se eu tentar enviar para a tela, obtenho vários resultados: echo
imprime todas as linhas em uma única linha, enquanto printf
imprime apenas a primeira linha:
#!/bin/bash
LS=$(ls -1 /bin)
echo $LS
printf $LS
Então, uma variável bash pode conter várias linhas?
Você precisa fazer uma citação dupla (e você deve variáveis de aspas duplas maioria dos casos):
echo "$LS"
Mas não use echo para imprimir conteúdo de variáveis, usando printf :
printf '%s\n' "$LS"
As novas linhas estão na variável. LS=$(ls -1)
define a variável LS
como a saída de ls -1
(que produz a mesma saída que ls
, a propósito, exceto quando a saída vai para um terminal), menos novas linhas à direita.
O problema é que você está removendo as novas linhas quando imprime o valor. Em um script de shell, $LS
não significa “o valor da variável LS
”, isso significa “pegue o valor de LS
, divida-o em palavras de acordo com IFS
e interprete cada palavra como um padrão glob " Para obter o valor de LS
, você precisa escrever "$LS"
ou, mais geralmente, colocar $LS
entre aspas duplas.
echo "$LS"
imprime o valor de LS
, exceto em alguns shells que interpretam caracteres de barra invertida e com exceção de alguns valores que começam com -
.
printf "$LS"
imprime o valor de LS
desde que não contenha nenhum caractere de porcentagem ou barra invertida e (com a maioria das implementações) não comece com -
.
Para imprimir exatamente o valor de LS
, use printf %s "$LS"
. Se você quiser uma nova linha no final, use printf '%s\n' "$LS"
.
Observe que $(ls)
não é, em geral, a lista de arquivos no diretório atual. Isso só funciona quando você tem nomes de arquivo suficientemente controlados. Para obter a lista de nomes de arquivos (exceto arquivos de ponto), você precisa usar um caractere curinga: *
. O resultado é uma lista de strings, não uma string, então você não pode atribuí-lo a uma variável de string; você pode usar uma variável de array files=(*)
em shells que os suportam (ksh93, bash, zsh).
Para mais informações, consulte Por que meu script de shell sufoca em espaços em branco ou outros caracteres especiais?
O acima mencionado
printf '%s\n' "$LS"
é a única solução correta.
Deixe-me demonstrar que as outras soluções propostas, ambas com echo
e printf
, simplesmente não funciona corretamente:
$ mkdir t
$ cd t
$ touch \n
$ LS=$(ls -l)
$ echo "$LS"
total 0
-rw-r--r-- 1 domain domain 0 Nov 5 06:12
$ printf "$LS\n"
total 0
-rw-r--r-- 1 domain domain 0 Nov 5 06:12
$ printf '%s\n' "$LS"
total 0
-rw-r--r-- 1 domain domain 0 Nov 5 06:12 \n
$ ls -l
total 0
-rw-r--r-- 1 domain domain 0 Nov 5 06:12 \n
$ rm \n
$ cd ..
$ rmdir t
$
(Também é possível testar com V=$(printf 'line0:\n\n\nline1.\n') printf '%s\n' "$V"
e variações.)
Considerando que \n
nos nomes de arquivos pode não ser tão comum, armazene git diff
em uma variável e suas chances de encontrando literal \n
aumentar dramaticamente.