Shell-Wildcard-Zeichenerweiterung stoppen?

87

Gibt es eine Möglichkeit für ein kompiliertes Befehlszeilenprogramm, bash oder csh mitzuteilen, dass in seinen Parametern keine Platzhalterzeichen erweitert werden sollen?

Zum Beispiel möchte man vielleicht einen Shell-Befehl wie:

foo *

um einfach den numerischen ASCII-Wert dieses Zeichens zurückzugeben.

hotpaw2
quelle

Antworten:

115

Nein. Die Erweiterung erfolgt, bevor der Befehl tatsächlich ausgeführt wird.
Sie können den Glob nur deaktivieren, bevor Sie den Befehl ausführen oder den Stern zitieren.

$ # quote it
$ foo '*'

$ # or escape it
$ foo \*

$ # or disable the glob (noglob)
$ set -f
$ foo *

$ # alternative to set -f
$ set -o noglob
$ # undo it by 
$ set +o noglob
c00kiemon5ter
quelle
3
Auch wenn es nichts zu erweitern gibt, gibt es keine Erweiterung. dh mit einem leeren pwd, echo *ist nur*
sam boosalis
7
@sam Dies hängt tatsächlich davon ab, wie Ihre Optionen eingestellt sind. Von tldp: "Wenn keine übereinstimmenden Dateinamen gefunden werden und die Shell-Option nullglobdeaktiviert ist, bleibt das Wort unverändert. Wenn die nullglobOption festgelegt ist und keine Übereinstimmungen gefunden werden, wird das Wort entfernt."
Chris Middleton
danke, ich hätte mich dafür qualifizieren sollen, dass das nur aus Beobachtung und nicht aus Verständnis war.
Sam Boosalis
@ c00kiemon5ter Wie mache ich das rückgängig set -f? Ist es unset -f?
Nam G VU
1
@NamGVUset +f
Yngvar Kristiansen
61

Obwohl ein Befehl selbst das Globbing nicht deaktivieren kann, kann ein Benutzer einer Unix-Shell anweisen, einen bestimmten Befehl nicht zu globalisieren. Dies wird normalerweise durch Bearbeiten der Konfigurationsdateien einer Shell erreicht. Angenommen, der Befehl foobefindet sich entlang des Befehlspfads, müsste der entsprechenden Konfigurationsdatei Folgendes hinzugefügt werden:

Für die sh-, bash- und ksh-Muscheln:

alias foo='set -f;foo';foo(){ command foo "$@";set +f;}

Für die csh- und tcsh-Shells:

alias foo 'set noglob;\foo \!*;unset noglob'

Für die zsh-Shell:

alias foo='noglob foo'

Der Befehlspfad muss nicht verwendet werden. Angenommen, der Befehl foo wird im Verzeichnis ~ / bin gespeichert, dann würde das Obige wie folgt lauten:

Für die sh-, bash- und ksh-Muscheln:

alias foo='set -f;foo';foo(){ ~/bin/foo "$@";set +f;}

Für die csh- und tcsh-Shells:

alias foo 'set noglob;$home/bin/foo \!*;unset noglob'

Für die zsh-Shell:

alias foo='noglob ~/bin/foo'

Alle oben genannten Tests wurden mit Apple OSX 10.9.2 getestet. Hinweis: Achten Sie beim Kopieren des obigen Codes darauf, Leerzeichen zu löschen. Sie können von Bedeutung sein.

Aktualisieren:

User geira hat darauf hingewiesen, dass im Fall einer Bash-Shell

alias foo='set -f;foo';foo(){ ~/bin/foo "$@";set +f;}

könnte durch ersetzt werden

reset_expansion(){ CMD="$1";shift;$CMD "$@";set +f;}
alias foo='set -f;reset_expansion ~/bin/foo'

das macht die Funktion foo überflüssig.

Einige Websites, die zum Erstellen dieses Dokuments verwendet wurden:

David Anderson
quelle
3
Dies hätte die akzeptierte Antwort sein müssen, da sie beweist, dass es tatsächlich möglich ist, das zu tun, was das OP will. Für einige noch bessere Methoden in Bash dokumentiert dieser Link die verschiedenen Optionen: blog.edwards-research.com/2011/05/preventing-globbing
Geira
@geira: Manchmal wird eine Antwort akzeptiert, bevor eine bessere Antwort veröffentlicht wird. Ich glaube, dass dies einer dieser Fälle sein kann. Ich glaube auch, dass die Antwortmarken, die von den Benutzern am nützlichsten sind, an erster Stelle stehen. Hinweis: Ich habe Ihre Eingabe zu meiner Antwort hinzugefügt.
David Anderson
@geira, das OP möchte, dass das kompilierte Programm mit der Shell kommuniziert. Die Antwort, dass es möglich ist, die Shell so zu konfigurieren, dass sie sich auf Befehl-für-Befehl-Basis wie gewünscht verhält, ist eine nützliche Antwort, und ich selbst würde diese akzeptieren, aber ich sehe Raum, um nicht zuzustimmen, ob sie vollständig auf den Punkt gebracht wird.
Charles Duffy
Die Tatsache , dass es kann getan werden , bedeutet nicht , dass es sollte getan werden. Es klingt überraschend und letztendlich unerwünscht, wenn sich das Verhalten der Shell von der angemessenen Erwartung des Benutzers für ausgewählte Befehle ändert.
Tripleee
@tripleee: Es gab eine Zeit, in der Leute Relais und Vakuumröhren erwarteten. Erwartet wurden Löcher in Pappe und Papierband gestanzt. Die Leute hielten Rechenschieber statt Taschenrechner und Telefone. Ich nehme an, für Sie wäre dies wünschenswert. Diese Zeiten waren mir egal. Ich genieße es zu sehen, was als nächstes kommt.
David Anderson
8

Die Erweiterung wird von der Shell durchgeführt, bevor Ihr Programm ausgeführt wird. Ihr Programm hat keine Ahnung, ob eine Erweiterung stattgefunden hat oder nicht.

   set -o noglob

schaltet die Erweiterung in der aufrufenden Shell aus, aber Sie müssen dies tun, bevor Sie Ihr Programm aufrufen.

Die Alternative besteht darin, Ihre Argumente zu zitieren, z

foo "*"
Brian Agnew
quelle
4
setopt scheint ein zsh-spezifischer Befehl zu sein. Wie in einem anderen Poster erwähnt, set -o noglobdeaktivieren Sie für Bash die Platzhaltererweiterung.
Wirawan Purwanto
Jetzt geändert. Vielen Dank
Brian Agnew
1

Achtung: Wenn keine Namen zur Maske passen, übergibt bash das Argument unverändert ohne Erweiterung!

Beweis (pa.py ist ein sehr einfaches Skript, das nur seine Argumente druckt):

 $ ls
f1.cc  f2.cc  pa.py
 $ ./pa.py *.cc
['./pa.py', 'f1.cc', 'f2.cc']
 $ ./pa.py *.cpp
['./pa.py', '*.cpp']
lesnik
quelle
3
Nicht immer. set -o nullgloboder shopt -s failglob, und dieses Verhalten wird sich ändern (auf zwei sehr unterschiedliche Arten).
Charles Duffy