Behandlung von Rückschlägen über Muscheln

9

Wie kann echound printfbehandeln Schrägstriche in zsh, bashund andere Schalen?

Unter zsh bekomme ich folgendes Verhalten:

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

Unter Bash scheinen die Dinge etwas konsistenter zu sein:

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

Aber konkreter: Wie kann ich eine Zeichenfolge mit Backslashes übergeben, z. B\\foo\bar\something .:

  • echo
  • printf
  • print

und genau die gleiche Zeichenfolge bekommen? (in zshund bash)?

Hier ist ein weiteres Experiment mit Funktionen in zsh:

function foo
{
    echo -E '$1'
}

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

Wie kann ich es nur drucken lassen \\here\is\some\path?

Update (Hinweis: Dies wurde jetzt in Stephanes Kommentar beantwortet.)

Ich habe in zsh 5.0.2 Folgendes versucht:

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

foo '\\some\path'

Aber das druckt $s?

Amelio Vazquez-Reina
quelle
3
Verwendung printf, echoist in dieser Hinsicht nicht tragbar.
Jordan
Sie "foo" -Funktion: Ersetzen Sie sie 'durch "und rufen Sie sie auf mit: foo '\\ here \ is \ some \ path' (andernfalls erhält die aufrufende Shell die Möglichkeit, das '\' zu interpretieren, bevor sie zur Funktion gelangt)
Olivier Dulac
2
Ihre Funktion wird verwendet, '$s\n'wenn sie hätte verwendet werden sollen '%s\n'.
cjm

Antworten:

12

zsh echoverhält sich wie bashim UNIX-Modus wie gewohnt. Das heißt, es wird \bauf das ASCII-BS-Zeichen erweitert, wie es die UNIX-Spezifikation erfordert.

Verwenden Sie nicht echo, um beliebige Zeichenfolgen anzuzeigen. Verwenden Sieprintf :

printf '%s\n' "$1"

print -r -- "$1"funktioniert auch aber ist ksh/ zshspezifisch.

echo -E - "$1"arbeiten mit zshund ich glaube einige BSDs.

cat << EOF
$1
EOF

funktioniert in jeder Bourne-ähnlichen Hülle, selbst in jenen aus einigen Jahrzehnten, in denen es keinen printfBefehl gab, aber einen neuen Prozess hervorbrachte, und ist heutzutage wirklich nicht mehr notwendig, wie wir es jetzt printfüberall haben.

Übrigens müssen Sie Backslashes in einer Shell-Befehlszeile vermeiden, da dies etwas Besonderes für die Shell ist (jede Shell außer rc). Also:

$ foo '\\foo\bar'

foo \\foo\barwürde die "\foo\bar"Zeichenfolge übergeben, an foodie der verlorene Backslash nicht neu erfunden werden kann.

Stéphane Chazelas
quelle
Danke Stephane. Seltsamerweise printf '%s\n' "$var"funktioniert die Konstruktion für mich über die Befehlszeile ( zsh 5.0.2dh die neueste), aber nicht innerhalb einer Funktion (siehe mein Update im OP). Warum?
Amelio Vazquez-Reina
1
Es ist printf '%s\n'nicht printf '$s\n'du willst. Beachten Sie, dass Sie Variablen in anderen Shells als zsh( "$1", nicht $1) angeben müssen und die Syntax der Standardfunktionsdefinition foo() { ...; }, obwohl jede Shell dies bashzulässt foo() any-command, function foo { .... }die kshSyntax ist.
Stéphane Chazelas
@Marcus, das ist eine Antwort auf eine andere Frage.
Stéphane Chazelas
1

neue Antwort: lies -r var

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

und anzuzeigen:

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

sollte arbeiten.

Also für deine foo Funktion:

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

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

alte Antwort unten (nicht antwortend, aber vielleicht nützlich ^^)

Ersetzen Sie einfach jedes \durch \\, um der Shell zu sagen, "dass es ein Literall ist, den \ich will". Andernfalls (zum Beispiel in zsh, in Ihrem Beispiel) könnte dies durchaus \b"1 Rücktaste" oder was auch immer bedeuten.

Sie könnten zum Beispiel sed verwenden:

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

(Sehen Sie, wie Sie dort auch "\" entkommen müssen, um sed dasselbe zu sagen: "Es ist ein Literall" \ "Ich möchte) (und beachten Sie, dass ich es mit '' und nicht" "umgeben habe, um zu vermeiden, dass die Shell interpretiert wird das meiste auch)

Olivier Dulac
quelle
Danke, aber wie ich im Titel erwähnt habe: Ich möchte vermeiden, Backslashes zu entkommen.
Amelio Vazquez-Reina
oops, ich werde bearbeiten ^^
Olivier Dulac
Vielen Dank! Scheint read -r varaber auf Eingabe von zu warten STDIN. Was ist, wenn ich es als Argument weitergebe? (zB foo \\here\is\some\path)
Amelio Vazquez-Reina
Die Shell interpretiert Backslashes. Aus diesem Grund sollten Sie das Argument wahrscheinlich in eine Lesung verschieben, siehe mein "foo" -Beispiel.
Olivier Dulac
1
iow: Sie möchten eine "nicht standardmäßige" Behandlung von Zeichenfolgen durch die Shell: Sie könnten Ihr Programm einfacher (und umfassender) an das anpassen lassen, was Sie möchten, anstatt zu versuchen, dass die Shell dieses Programm aufruft benimm dich wie du willst. Also: Übergeben Sie die Argumente (die "\" enthalten, die Sie nicht maskieren möchten) nach dem Start des Programms über "read -r" und nicht über die aufrufende Shell-Befehlszeile.
Olivier Dulac
1

Im Allgemeinen kann man nicht, weil Backslash ist die Escape - Zeichen (und als solche hat entgangen sein , wenn sein wörtlicher Wert erforderlich ist). BASH bietet zu diesem Zweck einfache Anführungszeichen. Sie können jedoch kein einfaches Anführungszeichen innerhalb einer Zeichenfolge in einfachen Anführungszeichen verwenden.

Was die echoDiskrepanz betrifft, handelt es sich um eine integrierte Diskrepanz, die sich zwischen den Shells (bis zu einem gewissen Grad) unterschiedlich verhalten kann. Zum Beispiel hat das eingebaute BASH eine -eOption, die es anweist, Backslash-Sequenzen zu interpretieren - damit erhalten Sie das Verhalten, das Sie in der Z-Shell gesehen haben.

Peterph
quelle