Em um shell do Linux, por que a barra invertida-nova não introduz espaço em branco?

3

Ao usar o shell do Linux, me deparo com a seguinte situação:

$ A=B\
> C
$ echo $A
BC

Na minha cabeça, quando a nova linha encontra um caractere de escape, ele não pode ser um caractere CR, mas ainda assim é uma nova linha. O echo $A deve ser interpretado como echo B newline C e a nova linha deve ser um IFS para echo . Portanto, a saída deve ser B C em vez de BC .

Por que recebo a saída que eu faço?

    
por user3872279 10.08.2014 / 13:07

3 respostas

3

Citação de man bash , seção QUOTING :

A non-quoted backslash (\) is the escape character. It preserves the literal value of the next character that follows, with the exception of <newline>. If a \<newline> pair appears, and the backslash is not itself quoted, the \<newline> is treated as a line continuation (that is, it is removed from the input stream and effectively ignored).

Isso permite que você interrompa sequências de comandos / comandos muito longos (canalizações e transformações de saída, etc.) em scripts em várias linhas para facilitar a leitura.

Para conseguir tratar a nova linha como você espera, apenas coloque o valor (e qualquer uso posterior da variável) entre aspas.

$ A="B
> C"
$ echo "$A"
B
C

Da mesma seção:

Enclosing characters in single quotes preserves the literal value of each character within the quotes. ...

Enclosing characters in double quotes preserves the literal value of all characters within the quotes, with the exception of $, ', \, and, when history expansion is enabled, !. The characters $ and ' retain their special meaning within double quotes. The backslash retains its special meaning only when followed by one of the following characters: $, ', ", \, or .

    
por 10.08.2014 / 13:12
1

Respondendo o "porquê" como "por que isso é útil":

A barra invertida-nova linha é usada para continuação de linha para dividir linhas longas:

Uma barra invertida no final de uma linha em um script de shell faz com que o shell ignore a nova linha para fins de execução do script. Isso normalmente é usado para dividir linhas longas em um arquivo de script em várias linhas de texto, que serão herdadas como uma única linha de script pelo shell.

Por exemplo, o comando

git log --tags --branches HEAD FETCH_HEAD ORIG_HEAD --graph --decorate --pretty=oneline --simplify-by-decoration

pode ser escrito como

git log --tags --branches HEAD FETCH_HEAD ORIG_HEAD \
    --graph --decorate --pretty=oneline --simplify-by-decoration
    
por 10.08.2014 / 13:33
0
A=B\
C

significa "A é igual à string B, seguida por uma nova linha que eu estou ignorando, seguida por um C"

Não há CR no que você digitou, até onde o shell o vê. Linux / Unix End Of Line é um Line Feed (LF), não CR. O CR é emitido como parte do manuseio do terminal. A maioria dos terminais precisa de um Line Feed para soltar uma linha e um Carriage Return para enviar o cursor de volta para a esquerda. O CR é inserido pelo kernel, ao enviar um Line Feed para o terminal, quando o terminal precisa disso - IOW, ele não é visível para o shell. Observe que, por exemplo, um editor visual pode separar o uso de CR e LF - o menor número de caracteres para a próxima parte da tela a ser reescrita pode envolver um LF (para ir diretamente para baixo sem alterar a coluna).

Ligeiramente mais confuso, há também uma tradução de entrada para teclados. A tecla Enter geralmente envia um retorno de carro (Control-M). Mas para reconhecer que um comando foi inserido, o shell precisa ver um End Of Line. Um parâmetro stty adicional, portanto, descreve ao manuseio do terminal do kernel, que uma entrada CR deve ser traduzida para um fim de linha. Então o shell ainda não vê um CR.

O resultado final é que o terminal envia:

A=B\<CR>C<CR>

O shell recebe:

A=B\<LF>C<LF>

O shell analisa isso como "oh, newline de barra invertida - eu simplesmente ignoro isso" e termina com:

A=BC<LF>

E na saída, o kernel modifica a sequência enviada ao terminal durante a entrada do comando como:

A=B\<CR><LF>C<CR><LF>

O processamento do kernel do tratamento de terminal é gerenciado pelo comando shell stty e, dependendo da implementação (Linux, Mac OS X, * BSD), os detalhes subjacentes devem estar em man termios , man tty_ioctl . man console_ioctl , etc.

    
por 10.08.2014 / 13:35