Forum: PC-Programmierung Bash: Argumente mit Sonderzeichen


von bash (Gast)


Lesenswert?

Unter Linux erstelle ich gerade ein Bash-File, welches mit zusätzlichen 
Argumenten aufgerufen werden soll. Dieses File wird von einem anderen 
Script gestartet, welches ich nicht mehr verändern kann. Mit dieser 
beispielhaften Zeile kann ich mir nun in meinem Bash-File sämtliche 
Argumente anzeigen lassen:
1
echo $@
Das ganze funktioniert an sich auch sehr gut.

Nun soll das neue Bash-File aber auch mit Sonderzeichen gestartet werden 
können. Also z.B. so hier:
1
./meinBashFile   mit\ Argument xy
Allerdings habe ich dann das Problem, dass das Sonderzeichen "\" 
entfernt wird.
Durch mein Echo hätte ich nun also gerne so etwas oder ähnliches 
gesehen: "mit\ Argument" "xy"

Klar, wenn ich nun zwei "\\"-Zeichen übergebe, oder das ganze in 
Anführungszeichen setzte, dann funktioniert wieder alles. Wie gesagt 
kann ich aber das Skript, welches mein neues Bash-File startet nicht 
mehr ändern.
Hätte jemand eine Idee, wie ich das Sonderzeichen im Bash-File sehen 
kann?

von Sven B. (scummos)


Lesenswert?

Hi, die Erklärung ist etwas konfus. Ich denke, sie wäre klarer, wenn du 
etwas weniger "Beispiel Beispiel" sagen würdest und konkrete Namen, 
Pfade und Strings nennen.

Aber falls ich sie richtig verstehe: nein, das Programm was dein Skript 
aufruft, interpretiert die Argumente offenbar als Shell-String. Dein 
Skript bekommt das \-Byte gar nicht mehr rein.

von MaWin (Gast)


Lesenswert?

bash schrieb:
> Nun soll das neue Bash-File aber auch mit Sonderzeichen gestartet werden
> können. Also z.B. so hier:./meinBashFile   mit\ Argument xy

Der Backslash wird bereits vor dem Aufruf von meinBashFile von deiner 
interaktiven shell expandiert und in diesem Fall einfach entfernt, weil 
Backslash-Leerzeichen kein valider Escapecode ist.

von MaWin (Gast)


Lesenswert?

bash schrieb:
> Wie gesagt
> kann ich aber das Skript, welches mein neues Bash-File startet nicht
> mehr ändern.

Kurze Korrektur zu meinem vorhergehenden Beitrag:
Da du es nicht interaktiv aufrufst, sondern aus einen anderen 
Bash-Script, MUSST du dieses Script ändern.
Eine andere Möglichkeit gibt es nicht, weil der Fehler in dem 
aufrufenden Script ist.

von dave4 (Gast)


Lesenswert?

Ich habe die Erklärung jetzt nicht ganz verstanden....

Ist der Backslash oder ist das Leerzeichen das zu übergebende 
Sonderzeichen?

Das übliche Vorgehen wäre es einfacher oder doppelte Anführungszeichen 
um das Argument zu machen.

von MaWin (Gast)


Lesenswert?

dave4 schrieb:
> Ist der Backslash oder ist das Leerzeichen das zu übergebende
> Sonderzeichen?

Der Backslash wird überhaupt nicht übergeben, sondern von der 
aufrufenden Shell expandiert. Da Backslash-Leerzeichen keine 
Escapesequenz ist, wird das in ein Leerzeichen expandiert.
Das heißt übergeben wird nur ein normales Leerzeichen.

von dave4 (Gast)


Lesenswert?

MaWin schrieb:
> Der Backslash wird überhaupt nicht übergeben, sondern von der
> aufrufenden Shell expandiert.

Desshalb die Frage ob der Backslash hinterher für irgendwas in das 
Script muss oder ob er das Leerzeichen escapen soll

von MaWin (Gast)


Lesenswert?

dave4 schrieb:
> Desshalb die Frage ob der Backslash hinterher für irgendwas in das
> Script muss oder ob er das Leerzeichen escapen soll

Die Frage verstehe ich nicht.
Der Backslash wird im aufrufenden Script entfernt.

von 🐧 DPA 🐧 (Gast)


Lesenswert?

MaWin schrieb:
> Der Backslash wird bereits vor dem Aufruf von meinBashFile von deiner
> interaktiven shell expandiert und in diesem Fall einfach entfernt, weil
> Backslash-Leerzeichen kein valider Escapecode ist.

Blödsinn. Das Escapen des slash ist an der stelle vollkommen i.o.
Bei der Expansion von $@  (und bei bash Arrays "${var[@]}") gibt es noch 
Besonderheiten. Schau dir mal folgendes Beispiel an:
1
printargs(){ 
2
  i=0
3
  for arg in "$@"
4
    do echo "arg $i: $arg"; i=$(expr $i + 1);
5
  done
6
}
7
8
ex1(){
9
  printargs "$@"
10
}
11
12
ex2(){
13
  printargs $@
14
}
15
16
echo "---- 1 ----"
17
printargs "a b" c
18
echo "---- 2 ----"
19
printargs a\ b c
20
echo "---- 3 ----"
21
printargs a b c
22
echo "---- 4 ----"
23
ex1 "a b" c
24
echo "---- 5 ----"
25
ex2 "a b" c

Man sieht da auch schön, dass der Slash nicht einfach nur entfernt wird, 
sondern das der folgende Space als String, bzw. hier als teil des 
Strings / Arguments behandelt wird, statt als Argument Trennzeichen 
geparst zu werden.

Es gibt auch noch "$*", die verhält sich wie eine normale String 
variable. Braucht man aber selten bis nie.

von g457 (Gast)


Lesenswert?

MaWin schrub:
> Der Backslash wird überhaupt nicht übergeben, sondern von der
> aufrufenden Shell expandiert.

Ersteres stimmt, zweiters nicht, siehe Doku [0].

> Da Backslash-Leerzeichen keine Escapesequenz ist, [..]

Doch, ist sie, und gültig ist sie auch, siehe Doku [0].

> [..] wird das in ein Leerzeichen expandiert.

Nein, wird es nicht. Das Leerzeichen (als Metazeichen, siehe Doku [0]) 
bleibt erhalten, und dient nicht als Argumenttrennzeichen, siehe Doku 
[0].

> Das heißt übergeben wird nur ein normales Leerzeichen.

Das wiederum stimmt, und zwar als "mit Argument" als ∗ein∗ Argument.

Dem TO bleibt nichts anderes übrig als mit aufgesplitteten Argumenten 
umgehen zu können oder den Bug im aufrufende Skript zu reparieren.

HTH

[0] man bash

von MaWin (Gast)


Lesenswert?

g457 schrieb:
> Doch, ist sie, und gültig ist sie auch, siehe Doku [0].

Ja gut. Jetzt haben wir das auch geklärt.
Es bleibt dabei, dass das aufrufende Script defekt ist.

von Christobal M. (c_m_1)


Lesenswert?

Vielleicht hilft das (habe OPs Problem nicht ganz verstanden).
Gezeigt wird der Unterschied zwischen double quotes (") und einfachen 
quotes (') - der Inhalt von double quotes wird von der shell 
interpretiert, also $variablen, aber auch file globs (*).
Als Zusatz noch die Auswirkung der Feldtrenner Variablen $IFS.
1
# vara=ABC
2
# echo $vara
3
ABC
4
# echo "$vara"
5
ABC
6
# echo '$vara'
7
$vara
8
# echo '$vara '$vara
9
$vara ABC
10
# varb='ABC\ DEF'
11
# echo $varb
12
ABC\ DEF
13
# for a in $varb; do echo $a ; done
14
ABC\
15
DEF
16
# echo $IFS
17
18
# export IFS='
19
> '
20
# for a in $varb; do echo $a ; done
21
ABC\ DEF

von Drago S. (mratix)


Lesenswert?

dave4 schrieb:
> Das übliche Vorgehen wäre es einfacher oder doppelte Anführungszeichen
> um das Argument zu machen.
Doppelte Anführungszeichen sind weiche.
Soll ein Inhalt nicht verändert werden, umschließt man es in harte ''. 
Shellkommandos werden immer so eingeschlossen.
Mit einem Backslash macht er doch den Zeilensprung und erkennt es nicht 
mehr als zusammenhöriges Argument.

Die bessere Frage ist, warum benötigt man ausgerechnet Backslashes? Die 
haben eine Sonderstellung.

Wenn etwa ein Netzwerkpfad übergeben werden soll, kann man sich Gedanken 
über die richtige Addressierung des Protokolls in Form 
smb://server/share/file machen.

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

Mister A. schrieb:
> Die bessere Frage ist, warum benötigt man ausgerechnet Backslashes?

Und dann auch noch ausgerechnet mit einem Leerzeichen dahinter.

von Drago S. (mratix)


Lesenswert?

Rolf M. schrieb:
> Und dann auch noch ausgerechnet mit einem Leerzeichen dahinter.
Wir kennen die Anwendung nicht. Daher tippe ich auf einen Pfad. 
root/webroot unter Windows oder so.
An sich stört das Leerzeichen nicht, wenn es nicht explizit zum Argument 
gehört (daher der Vorschlag mit den harten Füsschen).

Das nächst höhere wären die Backticks ``. Dann ist aber Ende.
Wenn ich es recht in Erinnerung habe, sind backticks die Aufforderung 
für eine Sub-shell. Das endet für ein Argument nicht gerade erfolgreich.

: Bearbeitet durch User
von pnp (Gast)


Lesenswert?

MaWin schrieb:
> Es bleibt dabei, dass das aufrufende Script defekt ist.

Das schrieb der TO aber schon selbst (im allerersten Beitrag).

von MaWin (Gast)


Lesenswert?

Mister A. schrieb:
> Das nächst höhere wären die Backticks ``

nein.
Die haben eine ganz andere Funktion.

von MaWin (Gast)


Lesenswert?

pnp schrieb:
> Das schrieb der TO aber schon selbst (im allerersten Beitrag).

Ja.
Aber er ging davon aus, dass es im aufgerufenen Script lösbar ist.
Es ist definitiv nicht im aufgerufenen Script lösbar, weil das 
aufrufende Script die Escape-Sequenz auflöst und den Backslash damit 
entfernt.

von Drago S. (mratix)


Lesenswert?

1
mratix@crodevo:/$ echo "bla\bla"
2
bla\bla
3
mratix@crodevo:/$ echo "bla\\bla"
4
bla\bla
5
mratix@crodevo:/$ echo "bla\\\\bla"
6
bla\\bla
7
mratix@crodevo:/$ echo 'bla\\bla'
8
bla\\bla
Geht doch. Hier der Unterschied von soft und hard.

MaWin schrieb:
> Die haben eine ganz andere Funktion.
1
mratix@crodevo:/$ echo `blabla`
2
blabla: Befehl nicht gefunden.
sieht definitiv nach subshell aus.

von MaWin (Gast)


Lesenswert?

Mister A. schrieb:
> sieht definitiv nach subshell aus.

Ja eben. Und was hat das jetzt hier mit dem Quoting und dem Escaping zu 
tun?
Richtig. Nichts.

von Drago S. (mratix)


Lesenswert?

MaWin schrieb:
> Richtig. Nichts.
Hast Recht. Immer wieder eine Freude hier mitzudenken...

von Karl (Gast)


Lesenswert?

MaWin schrieb:
> wird das in ein Leerzeichen expandiert.

Du weißt schon, was expandiert auf deutsch bedeutet?

von NILD69 (Gast)


Lesenswert?

Mister A. schrieb:



>
1
> mratix@crodevo:/$ echo `blabla`
2
> blabla: Befehl nicht gefunden.
3
>
> sieht definitiv nach subshell aus.

Erstzung, Command substitution:  $(command) =  `command`  (alte Form)
Das commandkonstrukt wird ausgeführt und das Ergebnis an die Stelle 
eingesetzt

das quoten ist doch gut beschrieben,
gibt halt eine Reihe Fälle

man bash
1
QUOTING
2
Quoting is used to remove the special meaning of certain characters or words to the shell. Quoting can be used to disable special treatment for special characters, to prevent reserved words from being recognized as such, and to prevent parameter expansion.
3
When the command history expansion facilities are being used, the history expansion character,usually !,must be quoted to prevent history expansion.
4
There are three quoting mechanisms: the escape character, single quotes, and double quotes.
5
A non-quoted backslash (\) is the escape character. It preserves the literal value of the next character that follows, with the exception of <newline>. If a \<newline> pair appears, and the backslash is not itself quoted, the \<newline> is treated as a line continuation (that is, it is removed from the input stream and effectively ignored).
6
Enclosing characters in single quotes preserves the literal value of each character within the quotes. A single quote may not occur between single quotes, even when preceded by a backslash.
7
Enclosing characters in double quotes preserves the literal value of all characters within the quotes, with the exception of $,`,\, and, when history expansion is enabled, !. The characters $ and ` retain their special meaning within double quotes. The backslash retains its special meaning only when followed by one of the following characters: $, `, ", \, or <newline>. A double quote may be quoted within double quotes by preceding it with a backslash. If enabled, history expansion will be performed unless an ! appearing in double quotes is escaped using a backslash. The backslash preceding the ! is not removed.
8
The special parameters * and @ have special meaning when in double quotes.
9
Words of the form $'string' are treated specially. The word expands to string, with backslash-escaped characters replaced as specified by the ANSI C standard.
10
Backslash escape sequences, if present, are decoded as follows:
11
...

von MaWin (Gast)


Lesenswert?

Karl schrieb:
> Du weißt schon, was expandiert auf deutsch bedeutet?

Ja. Danke für die sinnvolle Nachfrage.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.