Conteúdo do arquivo em variável unix com novas linhas

117

Tenho um arquivo de texto test.txt com o seguinte conteúdo:

text1
text2 

E quero atribuir o conteúdo do arquivo a uma variável UNIX, mas quando faço isso:

testvar=$(cat test.txt)
echo $testvar

o resultado é:

text1 text2

ao invés de

text1
text2 

Alguém pode me sugerir uma solução para isso?

Hugo
fonte

Respostas:

185

A atribuição não remove os caracteres de nova linha, é realmente echofazer isso. Você precisa simplesmente colocar aspas ao redor da string para manter essas novas linhas:

echo "$testvar"

Isso dará o resultado que você deseja. Veja a seguinte transcrição para uma demonstração:

pax> cat num1.txt ; x=$(cat num1.txt)
line 1
line 2

pax> echo $x ; echo '===' ; echo "$x"
line 1 line 2
===
line 1
line 2

A razão pela qual as novas linhas são substituídas por espaços não está inteiramente relacionada ao echocomando, mas sim uma combinação de coisas.

Quando fornecida uma linha de comando, bashdivide-a em palavras de acordo com a documentação da IFSvariável:

IFS: o separador de campo interno que é usado para divisão de palavras após a expansão ... o valor padrão é <space><tab><newline>.

Isso especifica que, por padrão, qualquer um desses três caracteres pode ser usado para dividir seu comando em palavras individuais. Depois disso, os separadores de palavras se foram, tudo o que resta é uma lista de palavras.

Combine isso com a echodocumentação (um bashcomando interno) e você verá por que os espaços são produzidos:

echo [-neE] [arg ...]: Produz os argumentos, separados por espaços, seguidos por uma nova linha.

Quando você usa echo "$x", força a xvariável inteira a ser uma única palavra de acordo com bash, portanto, não é dividida. Você pode ver isso com:

pax> function count {
...>    echo $#
...> }
pax> count 1 2 3
3
pax> count a b c d
4
pax> count $x
4
pax> count "$x"
1

Aqui, a countfunção simplesmente imprime o número de argumentos fornecidos. As variantes 1 2 3e o a b c dmostram em ação.

Em seguida, tentamos com as duas variações da xvariável. A única sem citações mostra que existem quatro palavras, "test", "1", "test"e "2". Adicionar as aspas torna uma única palavra "test 1\ntest 2".

paxdiablo
fonte
As citações ... isso é o que estava faltando! Obrigado!
anonimita
Também digno de nota: Trailing novas linhas serão removidos pelo próprio operador de substituição de comando: Experimente online!
Jonah
11

Isso se deve à variável IFS (Separador de campo interno) que contém nova linha.

$ cat xx1
1
2

$ A=`cat xx1`
$ echo $A
1 2

$ echo "|$IFS|"
|       
|

Uma solução alternativa é redefinir o IFS para não conter a nova linha, temporariamente :

$ IFSBAK=$IFS
$ IFS=" "
$ A=`cat xx1` # Can use $() as well
$ echo $A
1
2
$ IFS=$IFSBAK

Para REVERTER esta mudança horrível para a IFS:

IFS=$IFSBAK
DVK
fonte
Eu fiz essa alteração, mas agora minhas outras coisas não estão funcionando, diga-me para redefini-las.
Pooja25
Se você não precisa ir para uma variável, uma linha direta:echo "$(IFS=''; cat text.txt)"
Curtis Yallop
3

Apenas se alguém estiver interessado em outra opção:

content=( $(cat test.txt) )

a=0
while [ $a -le ${#content[@]} ]
do
        echo ${content[$a]}
        a=$[a+1]
done
DerWilts
fonte
3

Sua variável está definida corretamente por testvar=$(cat test.txt). Para exibir esta variável que consiste em caracteres de nova linha, basta adicionar aspas duplas, por exemplo

echo "$testvar" 

Aqui está o exemplo completo:

$ printf "test1\ntest2" > test.txt
$ testvar=$(<test.txt)
$ grep testvar <(set)
testvar=$'test1\ntest2'
$ echo "$testvar"
text1
text2
$ printf "%b" "$testvar"
text1
text2
Kenorb
fonte
0

O envdirutilitário fornece uma maneira fácil de fazer isso. envdirusa arquivos para representar variáveis ​​de ambiente, com mapeamento de nomes de arquivo para nomes env var e mapeamento de conteúdo de arquivo para valores env var. Se o conteúdo do arquivo contém novas linhas, o env var.

Veja https://pypi.python.org/pypi/envdir

Chris Johnson
fonte