Traitement des contre-obliques sur les obus

9

Comment faire echoet printftraiter antislashs dans zsh, bashet d' autres obus?

Sous zsh, j'obtiens le comportement suivant:

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

Sous bash , les choses semblent un peu plus cohérentes:

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

Mais plus concrètement: comment passer une chaîne contenant des barres obliques inverses comme\\foo\bar\something :

  • echo
  • printf
  • print

et obtenir exactement la même chaîne? (en zshet bash)?

Voici une autre expérience avec des fonctions dans zsh:

function foo
{
    echo -E '$1'
}

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

Comment puis-je simplement l'imprimer \\here\is\some\path?

Mise à jour (Remarque: il a maintenant été répondu dans le commentaire de Stéphane)

J'ai essayé ce qui suit dans zsh 5.0.2:

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

foo '\\some\path'

Mais cela imprime $s?

Amelio Vazquez-Reina
la source
3
Utilisation printf, echon'est pas portable à cet égard.
jordanm
votre fonction "foo": remplacez 'par ", et invoquez-la avec: foo '\\ ici \ est \ un \ chemin' (sinon le shell appelant a la possibilité d'interpréter le '\' avant d'arriver à la fonction)
Olivier Dulac
2
Votre fonction utilisée '$s\n'alors qu'elle aurait dû utiliser '%s\n'.
cjm

Réponses:

12

zsh echose comporte de manière standard, comme bashen mode UNIX. C'est-à-dire qu'il se développe \bau caractère ASCII BS comme l'exige la spécification UNIX.

Ne pas utiliser echopour afficher des chaînes arbitraires, utilisezprintf :

printf '%s\n' "$1"

print -r -- "$1"fonctionne également mais est ksh/ zshspécifique.

echo -E - "$1"travailler avec zshet je crois que certains BSD.

cat << EOF
$1
EOF

fonctionne dans n'importe quel shell de type Bourne, même ceux de quelques décennies où il n'y avait pas de printfcommande, mais il engendre un nouveau processus, et n'est vraiment pas nécessaire de nos jours comme nous l'avons maintenant printfpartout.

Et en passant, vous devez échapper les barres obliques inverses sur une ligne de commande du shell car c'est spécial pour le shell (tous les shell sauf rc), donc:

$ foo '\\foo\bar'

foo \\foo\barpasserait la "\foo\bar"chaîne à foolaquelle ne peut pas réinventer la barre oblique inversée perdue.

Stéphane Chazelas
la source
Merci Stéphane. Curieusement, la construction printf '%s\n' "$var"fonctionne pour moi sur la ligne de commande ( zsh 5.0.2c'est-à-dire la dernière), mais pas à l'intérieur d'une fonction (voir ma mise à jour dans l'OP). Pourquoi?
Amelio Vazquez-Reina
1
Ce n'est printf '%s\n'pas printf '$s\n'ce que tu veux. Notez que vous devez citer des variables dans d'autres shells que zsh( "$1", not $1) et la syntaxe de définition de fonction standard est foo() { ...; }, bien que n'importe quel shell, mais bashallow foo() any-command, et function foo { .... }est la kshsyntaxe.
Stéphane Chazelas
@Marcus, c'est une réponse à une question différente.
Stéphane Chazelas
1

nouvelle réponse: read -r var

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

et pour afficher:

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

devrait marcher.

Donc pour votre fonction foo:

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

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

ancienne réponse ci-dessous (ne répond pas, mais peut-être utile ^^)

remplacez simplement chacun \par \\pour dire au shell "que c'est un littéral que \je veux". sinon (par exemple dans zsh, dans votre exemple), cela pourrait bien \bsignifier "1 retour arrière", ou autre chose.

vous pouvez par exemple utiliser sed:

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

(voyez comment vous devez également y échapper "\", pour dire à sed la même chose: "c'est un littéral" \ "je veux) (et remarquez que je l'entoure de '' et non" "pour éviter que le shell interprète la plupart aussi)

Olivier Dulac
la source
Merci mais comme je l'ai mentionné dans le titre: je veux éviter d'échapper aux barres obliques inverses.
Amelio Vazquez-Reina
oups, je vais éditer ^^
Olivier Dulac
Merci! Mais read -r varsemble attendre la contribution de STDIN. Et si je le passe en argument? (ex. foo \\here\is\some\path)
Amelio Vazquez-Reina
le shell interprète les contre-obliques. C'est pourquoi vous devriez probablement déplacer l'argument en le lisant, voir mon exemple "foo".
Olivier Dulac
1
iow: vous voulez une gestion "non standard" des chaînes par le shell: vous pourriez plus facilement (et plus largement) faire en sorte que votre programme soit conforme à ce que vous voulez, au lieu d'essayer d'avoir le shell-invoquant-ce-programme pour comportez-vous comme vous voulez. Donc: passez les arguments (ceux contenant "\" que vous ne voulez pas échapper) une fois que le programme est démarré, via "read -r", et non sur sa ligne de commande d'invocation de shell.
Olivier Dulac
1

D'une manière générale, vous ne pouvez pas, car la barre oblique inverse est le caractère d'échappement (et en tant que tel doit être échappé lorsque sa valeur littérale est requise). BASH fournit des guillemets simples à cet effet, mais vous ne pouvez pas utiliser d'échappement un guillemet simple dans une chaîne entre guillemets simples.

Quant à la echodifférence, il s'agit d'un intégré qui peut se comporter différemment selon les coques (dans une certaine mesure). Par exemple, le BASH intégré a une -eoption qui lui dit d'interpréter les séquences de barre oblique inverse - avec lui, vous obtiendriez le comportement que vous avez vu dans le shell Z.

peterph
la source