Tratamento de barras invertidas através de shells

8

Como echo e printf tratam as barras invertidas em zsh , bash e outras shells?

Em zsh , obtenho o seguinte comportamento:

$ echo "foo\bar\baz"
foaaz
$ echo "foo\bar\baz"
foaaz
$ echo 'foo\bar\baz'
foaaz
$ echo 'foo\bar\baz'
foo\bar\baz

Em bash , as coisas parecem um pouco mais consistentes:

bash$ echo "foo\bar\baz"
foo\bar\baz
bash$ echo 'foo\bar\baz'
foo\bar\baz
bash$

Mas mais concretamente: Como posso passar uma string contendo barras invertidas, como \foo\bar\something para:

  • echo
  • printf
  • print

e obter exatamente a mesma string? (em zsh e bash )?

Aqui está outro experimento com funções no zsh:

function foo
{
    echo -E '$1'
}

$ foo \here\is\some\path
$1

Como posso ter apenas imprimir \here\is\some\path ?

Atualização (Nota: isto agora foi respondido no comentário de Stephane)

Eu tentei o seguinte no zsh 5.0.2:

function foo
{
    printf '$s\n' $1 
}

foo '\some\path'

Mas isso imprime $s ?

    
por Amelio Vazquez-Reina 28.03.2013 / 19:38

3 respostas

10

zsh echo se comporta da maneira padrão, como bash no modo UNIX. Ou seja, ele expande \b para o caractere ASCII BS, conforme exigido pela especificação UNIX.

Não use echo para exibir strings arbitrárias, use printf :

printf '%s\n' "$1"

print -r -- "$1" também funciona, mas é ksh / zsh específico.

echo -E - "$1" trabalha com zsh e acredito em alguns BSDs.

cat << EOF
$1
EOF

funciona em qualquer shell parecido com o Bourne, mesmo em algumas décadas, quando não havia nenhum comando printf , mas gerou um novo processo, e não é necessário atualmente, já que agora temos printf em todos os lugares.

E, a propósito, você precisa escapar das barras invertidas em uma linha de comando do shell, já que é especial para o shell (cada shell, mas rc ), então:

$ foo '\foo\bar'

foo \foo\bar passaria a string "\foo\bar" para foo , que não pode reinventar a barra invertida perdida de volta.

    
por 28.03.2013 / 21:35
1

nova resposta: read -r var

-r  raw input - disables interpretion of backslash escapes and line-continuation in the read data

e para exibir:

printf "%s" "$var"
echo "$var"

deve funcionar.

Então, para sua função foo:

function foo
{
    read -r var
    echo -E "var is : ${var}"
}

$ foo 
\here\is\some\path
var is : \here\is\some\path

resposta antiga abaixo (não respondendo, mas talvez útil ^^)

apenas substitua cada \ por \ para informar ao shell "que é um literal \ ". caso contrário (por exemplo, em zsh, no seu exemplo), pode ser que \b signifique "1 backspace", ou o que for.

você poderia, por exemplo, usar sed:

sed -e 's,\,\\,g' < the_original > the_escaped_backslaches_version

(veja como você também precisa escapar "\", para dizer a mesma coisa: "é um literall" "eu quero) (e observe que eu o rodeio por '' e não" "para evitar shell para interpretar a maior parte também)

    
por 28.03.2013 / 19:59
1
De um modo geral, você não pode, porque a barra invertida é o caractere de escape (e, como tal, deve ser evitado quando seu valor literal for necessário). O BASH fornece aspas simples para esse propósito, no entanto, você não pode usar escape de uma aspa simples dentro de uma string entre aspas simples.

Quanto à discrepância de echo , é um modelo interno que pode se comportar de maneira diferente em shells (até certo ponto). Por exemplo, o BASH built-in tem uma opção -e que diz para interpretar seqüências de backslash - com ele você obteria o comportamento que você viu no shell Z.

    
por 28.03.2013 / 20:10