Não é a impressão, é a substituição de comando que faz isso. Está definido para fazer isso. A partir da descrição do POSIX :
The shell shall expand the command substitution by executing command in a subshell environment and replacing the command substitution with the standard output of the command, removing sequences of one or more {newline} characters at the end of the substitution.
Note que remove todas novas linhas iniciais, não apenas uma.
Em um caso comum, você usaria a substituição de comando para capturar uma saída de uma linha, digamos osrev=$(uname -r)
. Os utilitários geralmente imprimem uma nova linha à direita, para conveniência do usuário na linha de comando. Mas em um shell script, você pode querer usar essa string como parte de outra, digamos um nome de arquivo: filename=blahblah-$osrev.dat
. E, nesse caso, a nova linha seria apenas um incômodo.
E, claro, um echo
simples adicionará uma nova linha final em qualquer caso.
Se você quiser o conteúdo do arquivo como está na variável, a solução alternativa é adicionar um caractere extra na substituição do comando e removê-lo posteriormente:
printf "foo\nbar\n\n" > file
string=$(cat file; echo x)
string=${string%x}
printf '%q\n' "$string"
que gera $'foo\nbar\n\n'
, mostrando as novas linhas finais presentes.
Dependendo do que você pretende fazer com os dados, pode haver outras formas. Por exemplo. um while read
loop, ou mapfile
do Bash, se acontecer de você querer processar o arquivo linha por linha.