Onde o caractere de linha de fuga foi removido da minha substituição de comando?

14

O código a seguir descreve melhor a situação. Por que a última linha não está exibindo o caractere de nova linha à direita? A saída de cada linha é mostrada no comentário. Estou usando o GNU bash, versão 4.1.5

     echo -n $'a\nb\n'                  | xxd -p  # 610a620a  
           x=$'a\nb\n'   ; echo -n "$x" | xxd -p  # 610a620a
     echo -ne "a\nb\n"                  | xxd -p  # 610a620a
x="$(echo -ne "a\nb\n")" ; echo -n "$x" | xxd -p  # 610a62
    
por Peter.O 31.07.2011 / 06:07

2 respostas

18

A função de substituição de comandos $() (e seu primo o backtick) remove especificamente as novas linhas finais. Este é o comportamento documentado e você deve estar sempre ciente disso ao usar a construção.

Novas linhas dentro do corpo do texto não são removidas pelo operador de substituição, mas elas também podem ser removidas quando se faz a divisão de palavras no shell, então, o resultado depende do uso de citações ou não. Observe a diferença entre esses dois usos:

$ echo -n "$(echo -n 'a\nb')"
a
b

$ !! | xxd -p
610a62

$ echo -n  $(echo -n 'a\nb')
a b

$ !! | xxd -p   
612062

No segundo exemplo, a saída não foi citada e a nova linha foi interpretada como uma divisão de palavras, fazendo com que ela apareça na saída como um espaço!

    
por 31.07.2011 / 08:01
6

Ao utilizar a substituição de comandos, o shell executa os comandos em um subshell, retornando seu stdout. nesse processo, os caracteres IFS perdem sua importância (se não forem citados), pois o comando retorna palavras simples, então os caracteres posteriores são removidos. Por exemplo:

$ echo "$(echo -e '\n')" | wc
 1       0       1

$ echo -e '\n' | wc
2       0       2

e mais praticamente, pwd funcionará mesmo se o nome do diretório tiver uma nova linha no meio, mas $(pwd) não.

A solução usual é adicionar algo no final do seu comando e retirá-lo depois disso.

    
por 31.07.2011 / 08:01