Bash: Übergeben von Befehlszeilenargumenten mit Sonderzeichen

31

Ich habe mir ein Linux-Programm geschrieben program, das einen regulären Ausdruck als Eingabe benötigt.

Ich möchte das Programm in der bashShell aufrufen und diesen regulären Ausdruck als Befehlszeilenargument an das Programm übergeben (es gibt auch andere Befehlszeilenargumente). Ein typischer regulärer Ausdruck sieht aus wie

[abc]\_[x|y]

Leider sind die Zeichen [, ]und |Sonderzeichen in bash. Also anrufen

program [abc]\_[x|y] anotheragument

funktioniert nicht Gibt es eine Möglichkeit, den Ausdruck mit Escape-Zeichen, Anführungszeichen usw. zu übergeben?

(Der Aufruf program "[abc]\_[x|y] anotheragument"funktioniert auch nicht, da die beiden Argumente als eins interpretiert werden.)

Christian
quelle

Antworten:

27

Du kannst entweder

  1. Entfliehen Sie jedem einzelnen Sonderzeichen einen Backslash (wie in \[abc\]_\[x\|y\]) oder
  2. Doppelte Anführungszeichen für das gesamte Argument (wie in "[abc]_[x|y]").

BEARBEITEN: Wie einige betont haben, verhindert Dobleqouting weder die Variablenerweiterung noch das Ersetzen von Befehlen. Wenn Ihre Regex also etwas enthält, das von Bash als eines davon interpretiert werden kann, verwenden Sie stattdessen einfache Anführungszeichen .

Antichris
quelle
4
In der Bash werden beim Anführungszeichen keine expandierenden Variablen oder Parameter , keine Befehlsersetzung in Form oder keine arithmetische Expansion , Historienexpansion oder kein Backslash-Escaping umgangen . Verwenden Sie stattdessen einfache Anführungszeichen. Weitere Informationen finden Sie auf der Manpage des Bash-Handbuchs im Abschnitt "Zitieren". "$HOME""${USER:-root}""$(date)""`date`""$((1 + 2))""!!""\\"
Flimm
25

Verwenden Sie einfache Anführungszeichen. Einfache Anführungszeichen stellen sicher, dass keines der Zeichen interpretiert wird.

$ printf %s 'spaces  are  not  interpreted away
neither are new lines
nor variable names $TESTING
nor square brackets [TESTING]
nor pipe characters or redirection symbols | > <
nor the semicolon ;
nor backslashes \a \b \c \\
the only thing that does not work is the single quote itself
'

Es gibt zwei Lösungen, wenn Sie ein einzelnes Anführungszeichen einbetten müssen:

$ printf '%s\n' '[ Don'"'"'t worry, be happy! ]'
[ Don't worry, be happy! ]
$ printf '%s\n' '[ Don'\''t worry, be happy! ]'
[ Don't worry, be happy! ]
Flimm
quelle
Du hast Recht. +1
Antichris
6

Pro man bash

Es gibt drei Anführungszeichen : das Escape-Zeichen , einfache Anführungszeichen und doppelte Anführungszeichen.

Ein Backslash ( \ ) ohne Anführungszeichen ist das Escape-Zeichen . Der Literalwert des nächsten folgenden Zeichens wird beibehalten, mit Ausnahme von <newline>. Wenn ein \ <newline> -Paar angezeigt wird und der umgekehrte Schrägstrich nicht in Anführungszeichen steht, wird \ <newline> als Zeilenfortsetzung behandelt (dh, es wird aus dem Eingabestream entfernt und effektiv ignoriert).

Das Einschließen von Zeichen in einfache Anführungszeichen behält den Literalwert jedes Zeichens in den Anführungszeichen bei. Ein einfaches Anführungszeichen darf nicht zwischen einfachen Anführungszeichen stehen, auch wenn ein Backslash vorangestellt ist.

Wenn Sie Zeichen in doppelte Anführungszeichen setzen, bleibt der Literalwert aller Zeichen in den Anführungszeichen erhalten, mit Ausnahme von $ , ` , \ und, wenn die Verlaufserweiterung aktiviert ist ,! . Die Zeichen $ und ` behalten in Anführungszeichen ihre besondere Bedeutung. Der Backslash behält seine spezielle Bedeutung nur bei, wenn auf ihn eines der folgenden Zeichen folgt: $ , ` , " , \ oder <newline> . Ein doppeltes Anführungszeichen kann in doppelten Anführungszeichen gesetzt werden, indem ein Backslash vorangestellt wird wird durchgeführt, es sei denn ein! Das Erscheinen in doppelten Anführungszeichen wird mit einem Backslash abgeschlossen. Der Backslash vor dem ! wird nicht entfernt.

Die Sonderparameter * und @ haben in doppelten Anführungszeichen eine besondere Bedeutung (siehe PARAMETER unten).

Wörter der Form $ ' string ' werden speziell behandelt. Das Wort wird zu einer Zeichenfolge erweitert , wobei mit einem Backslash versehene Zeichen gemäß dem ANSI C-Standard ersetzt werden. Escape-Sequenzen für umgekehrte Schrägstriche werden, falls vorhanden, wie folgt dekodiert:

       \ a      alert (bell)
        \ b      backspace
        \ e 
       \ e      ein Escapezeichen
        \ f      Formularvorschub
        \ n      neue Zeile
        \ r      Wagenrücklauf
        \ t      horizontale Tabulatortaste
        \ v      vertikale Tabulatortaste
        \\      Backslash
        \ '      einfaches Anführungszeichen
        \ "      doppeltes Anführungszeichen
        \ nnn    die Acht-Bit-Zeichen, dessen Wert der Oktalwert nnn ist
              (ein bis drei Ziffern)
       \ x HH    das Acht-Bit-Zeichen, dessen Wert der Hexadezimalwert HH ist
              (ein oder zwei hexadezimale Ziffern)
       \ u HHHH das Unicode-Zeichen (ISO / IEC 10646), dessen Wert ist
              der Hexadezimalwert HHHH (eine bis vier Hexadezimalstellen )
        \ U HHHHHHH
              das Unicode-Zeichen (ISO / IEC 10646) mit dem Wert
              der hexadezimale Wert HHHHHHHH (eine bis acht Hexadezimalstellen )
        \ c x     ein Steuer- x Zeichen

Das erweiterte Ergebnis wird in einfache Anführungszeichen gesetzt, als ob das Dollarzeichen nicht vorhanden gewesen wäre.

Eine Zeichenfolge in doppelten Anführungszeichen mit vorangestelltem Dollarzeichen ( $ " string " ) bewirkt, dass die Zeichenfolge entsprechend dem aktuellen Gebietsschema übersetzt wird. Wenn das aktuelle Gebietsschema C oder POSIX ist , wird das Dollarzeichen ignoriert. Wenn die Zeichenfolge übersetzt und ersetzt wird, wird die Ersetzung in doppelte Anführungszeichen gesetzt.

Evan Carroll
quelle
2

Sie können einen Backslash ( \) vor Sonderzeichen verwenden, um diese wie folgt zu maskieren:

john @ awesome: ~ # echo \ &
&
John T
quelle
2

Obwohl es möglicherweise nicht als regulärer Ausdruck nützlich ist, können einige Zeichenfolgen als Bash-Variablennamen interpretiert werden. Verwenden Sie einfache Anführungszeichen anstelle von doppelten Anführungszeichen, um dies zu verhindern und zu vermeiden, dass sie erweitert werden:

program '[abc]_[x|y]' anotherargument

Zitieren Sie jedes Argument separat (wenn es zitiert werden muss), damit es als unabhängige Argumente interpretiert wird. In einigen Fällen können Sie auch Arrays verwenden:

param_array=('[abc]_[x|y]' anotherargument)    # create an array
param_array+=(yetanother)     # append another element to the array
program "${param_array[@]}"   # use the array elements as arguments to program
Bis auf weiteres angehalten.
quelle
1
program "[abc]_[x|y]"
program "[abc]_[x|y]" anotherargument
Witek
quelle
0

Es sollte gut funktionieren, wenn Sie ihnen entkommen:

  programm \[abc\]_\[x\|y\]
Bobby
quelle
0

Woher kommt das Muster? Ist es behoben oder von einem Benutzer? Ist es der Benutzer, der das Skript auf dem lokalen System aufruft, oder eine entfernte Person?

Sie setzen Daten in Anführungszeichen, um zu verhindern, dass die Shell sie interpretiert. Es gibt zwei Möglichkeiten:

  1. Doppelte Anführungszeichen, die noch eine Interpretation erlauben ($ expand und `backticks`)
  2. Einfache Anführungszeichen, die buchstäblich alles durchgehen

Da $es sich um ein gültiges Zeichen in regulären Ausdrücken (Zeilenende / Puffer) handelt, möchten Sie wahrscheinlich einfache Anführungszeichen verwenden, um den regulären Ausdruck zu speichern, es sei denn, Sie speichern ihn in einer Variablen. Wenn Sie nicht vertrauenswürdig beliebige Daten von jemandem nehmen, müssen Sie ersetzen 'mit '"'"'und wickeln dann in einfachen Anführungszeichen.

Beachten Sie, dass [abc]_[x|y]Sie xoder yübereinstimmen möchten , während tatsächlich eines der drei Zeichen übereinstimmt xy|. Die eckigen Klammern entsprechen den Zeichen innerhalb und nur -für Bereiche und a ^am Anfang für die Negation. So [abc]_(x|y)könnte das sein , was Sie gemeint, und die Klammern sind die Zeichen , die zu schälen sind etwas Besonderes. Eckige Klammern sind nichts Besonderes an der Schale, sie sehen einfach so aus, wie sie sind. Doppelte eckige Klammern [[ ... ]]sind etwas Besonderes.

Phil P
quelle
Dies ist eine der richtigsten Antworten hier (ich schätze besonders die Anweisung zum Ersetzen 'durch '"'"'), aber es ist immer noch nicht richtig. [IS ein spezielles Zeichen für Shell, wird es in Platzhaltern verwendet, wenn Pfaderweiterungen durchgeführt werden (welche Shell für alles, was nicht in Anführungszeichen steht, verwendet wird).
jpalecek
Es ist in einigen Kontexten, wie z. B. beim Subskriptieren von Variablen oder beim Globbing, etwas Besonderes, aber Sie können immer noch tippen foo=a[b]und dann echo $foosehen, dass die Zeichenfolge kein Anführungszeichen benötigt. Du hast recht, ich war zu kurz.
Phil P
Wenn Sie Pech haben, befindet sich eine Datei abim aktuellen Verzeichnis und fooenthält dann abeher als a[b]. Zitieren Sie Ihre eckigen Klammern, Leute.
Clacke
(Aus Gründen der Klarheit: Ich zitiere (wie in der ursprünglichen Antwort klargestellt wurde, wo ich auf das Zitieren gedrängt habe), und dies ist eine Nebenentgleisung, die ich anspreche). Diese Behauptung hat mich überrascht und ich habe sie getestet. Es ist nicht wahr in zsh oder bash, aber es ist wahr in BSD / bin / sh. Dies ist gegen POSIX und stellt kein Standardverhalten dar. Sie müssen also ein Angebot einreichen, um damit umzugehen. In zsh können Sie setopt glob_assigndieses Verhalten auch aktivieren, daher ist das Zitieren die sicherste Antwort.
Phil P