Por que 'sudo -i' mas não 'sudo' remove caracteres de nova linha? [duplicado]

9

O que pode explicar os exemplos abaixo e como posso corrigir isso, de preferência sem acrobacias de citação pesadas? Eu estou usando o $n para simular várias seqüências de comandos de linha, apenas para distrair você da questão real.

~$ n=$'\n'; sudo -i echo "line1${n}line2${n}"
line1line2
~$

mas

~$ n=$'\n'; sudo echo "line1${n}line2${n}"
line1
line2

~$
    
por argle 03.06.2018 / 12:08

2 respostas

10

A execução desse sudo -i echo $'line1\nline2' sob strace mostra que o Bash é iniciado assim:

9183  execve("/bin/bash", ["-bash", "--login", "-c", "echo line1\\nline2\\n"], ...

Agora, strace apresenta caracteres especiais com escapes invertidos quando exibe as strings, então o que o Bash realmente obtém como argumento para -c é echo line1[backslash][newline]line2[backslash][newline] e para o shell, uma barra invertida no final de uma linha marca uma linha de continuação e remove a barra invertida e a seguinte nova linha.

Sem -i , sudo executa echo diretamente, sem passar pelo shell:

9189  execve("/bin/echo", ["echo", "line1\nline2\n"], ... 

Aqui, uma nova linha literal vai para echo e echo imprime isso.

A ideia aqui deve ser que sudo tente adicionar uma camada de shell escapando para acomodar o fato de que sh -c toma uma string única , enquanto sudo toma o comando como argumentos distintos.

Compare os seguintes casos:

sudo escapa do espaço (este é apenas o nome do comando, sem argumentos!):

$ sudo -i 'echo foo'
-bash: echo foo: command not found

sudo escapa da barra invertida, de modo que isso realmente funciona (o echo do Bash não processa a barra invertida):

$ sudo -i echo 'foo\bar'
foo\bar

O mesmo com uma guia:

$ sudo -i echo $'foo\tbar'
foo     bar

Aqui, não há nenhuma citação extra na barra invertida, então Bash a remove enquanto processa a linha de comando do shell ( b não é um caractere especial para o shell, e não precisa ser citado. Isso é basicamente o mesmo que bash -c 'echo foo"b"ar' ):

$ bash -c 'echo foo\bar'
foobar

O problema é que você não pode escapar de uma nova linha com uma barra invertida, e sudo não parece levar isso em conta.

Em qualquer caso, a citação de questões como essa provavelmente ficará um pouco mais fácil se você armazenar os comandos desejados em um arquivo e executá-los como um script.

    
por 03.06.2018 / 14:34
1

Você pode alterar a estrutura do comando:

echo "echo \"line1${n}line2${n}\"" | sudo -i bash -s

Dessa forma, sudo não vê o argumento e, portanto, não pode interferir.

    
por 03.06.2018 / 19:59