GNU findet und maskiert die {} für einige Shells - welche?

34

Die Manpage für GNU find lautet:

-exec command ;
    [...] The  string `{}'  is  replaced  by the current 
    file name being processed everywhere it occurs in the 
    arguments to the command, not just in arguments where 
    it is alone, as in some  versions  of  find.
    Both  of  these  constructions might need to be escaped 
    (with a `\') or quoted to protect them from expansion 
    by the shell. 

Das ist vom Mann bis find(GNU findutils) 4.4.2.

Jetzt habe ich dies mit Bash und Dash getestet, und beide müssen nicht {}maskiert sein. Hier ist ein einfacher Test:

find /etc -name "hosts" -exec md5sum {} \; 

Gibt es eine Muschel, für die ich die Zahnspangen wirklich maskieren muss? Beachten Sie, dass es nicht davon abhängt, ob die gefundene Datei ein Leerzeichen enthält (wird von bash aufgerufen):

find ~ -maxdepth 1 -type d -name "U*" -exec ls -d {} \; 
/home/stefan/Ubuntu One

Dies ändert sich, wenn die gefundene Datei an eine Subshell übergeben wird:

find ~ -maxdepth 3 -type d -name "U*" -exec bash -c 'ls -d {}' \; 
ls: cannot access /home/stefan/Ubuntu: No such file or directory
ls: cannot access One: No such file or directory

was gelöst werden kann durch:

find ~ -maxdepth 3 -type d -name "U*" -exec bash -c 'ls -d "$0"' {} \;

im Kontrast zu:

find ~ -maxdepth 3 -type d -name "U*" -exec bash -c 'ls -d "{}"' \; 
/home/stefan/Ubuntu One

Aber darum geht es doch nicht in der Manpage, oder? Also, welche Muschel behandelt {}auf eine andere Art und Weise?

Benutzer unbekannt
quelle
@Volker Siegel: Ihre Bearbeitung mag in guter Absicht geschehen sein, aber ich habe mein aktuelles Find-Handbuch überprüft und Ihre Korrekturen sind falsch. Sie haben auch die Gelegenheit verpasst, Ihre Änderungen zusammenzufassen, was eine schlechte Angewohnheit ist. Also mache ich einen Rollback Ihrer Änderungen. Entschuldigung, Mann.
Benutzer unbekannt
Oh, danke, dass du es zurückgerollt hast, wenn es etwas kaputt gemacht hat. Ich erinnerte mich, dass der Text-Compiler, der das Manpage-Format generiert, das zum Generieren dieser "typografischen Anführungszeichen" verwendet wird, ein Artefakt der Rendering-Definition ist. Es kann auch in TeX gerendert werden, um eine perfekte Formatierung des Ausdrucks zu erzielen. Ich habe die Anführungszeichen bemerkt, weil sie die Syntaxhervorhebung verwirrten. Ich nahm an, dass das ungewöhnliche erste Zitat falsch ist, wenn es im Code verwendet wird, und nehme das immer noch an. Beachten Sie, dass sich die beiden Änderungen auf den Beschreibungstext und nicht auf den Code beziehen. Wenn wir sie also als Typografie betrachten - als ästhetische Wiedergabe - dann haben sie Recht.
Volker Siegel
Sieht so aus, als würde in der Darstellung der Info-Ausgabe auf beiden Seiten dasselbe Zitat verwendet. Es besteht kein Zweifel, dass meine Änderung sich vom Original unterschied. Sie haben Recht. Aber hat es ein Problem verursacht? (Ich betrachte das erste Zitat als einen Fehler in der Definition für das Rendern von Männern. Soweit ich weiß, ist es der einzige Fall von Typografie.)
Volker Siegel,
Ich habe gerade überprüft: "{}" funktioniert nicht in der Befehlszeile. Das ist technisch korrekt, aber ich mag es nicht, dass ein ahnungsloser Benutzer einen seltsamen Fehler bekommt, wenn er versucht, ihn zu kopieren und einzufügen.
Volker Siegel
@VolkerSiegel: Es ist Prosatext, kein Code, also was soll ein Benutzer hier kopieren und einfügen? Und es ist ein Zitat der Manpage von 2011. Ich sehe keinen Wert, der die Passage korrigiert, um dann darauf hinzuweisen, warum ich Korrekturen an der Manpage vorgenommen habe. Das Thema ist kompliziert genug. Wenn dies Ihre Frage wäre, würde ich nicht versuchen, Sie davon zu überzeugen, die Manpage genau zu zitieren, aber für meine Frage bin ich nicht in der Stimmung, Kompromisse einzugehen. Zitieren ist Zitieren.
Benutzer unbekannt

Antworten:

26

Fazit : Wenn es jemals eine Shell gab, die erweitert wurde {}, ist sie mittlerweile wirklich alt.

In dem Bourne - Shell und in POSIX-compliant shells, Zahnspange ( {und }) sind gewöhnliche Zeichen ( im Gegensatz zu, (und )die Worttrennzeichen sind wie ;und &und [und ]die Globbing Zeichen). Die folgenden Zeichenfolgen sollen alle wörtlich gedruckt werden:

$ echo { } {} {foo,bar} {1..3}
{ } {} {foo,bar} {1..3}

Ein Wort, das aus einer einzelnen geschweiften Klammer besteht, ist ein reserviertes Wort . Dies ist nur dann etwas Besonderes, wenn es das erste Wort eines Befehls ist.

Ksh implementiert die Klammererweiterung als inkompatible Erweiterung der Bourne-Shell. Dies kann mit ausgeschaltet werden set +B. Bash emuliert in dieser Hinsicht ksh. Zsh implementiert auch die Klammererweiterung. dort kann es mit set +Ioder setopt ignore_bracesoder ausgeschaltet werden emulate sh. Keine dieser Shells wird {}auf jeden Fall erweitert, auch wenn es sich um eine Teilzeichenfolge eines Wortes handelt (z. B. foo{}bar), da sie häufig in Argumenten für findund verwendet wird xargs.

Single Unix v2 merkt das an

In einigen historischen Systemen werden die geschweiften Klammern als Steueroperatoren behandelt. Um zukünftige Standardisierungsaktivitäten zu unterstützen, sollten tragbare Anwendungen die Verwendung nicht zitierter Klammern zur Darstellung der Zeichen selbst vermeiden. Es ist möglich, dass eine zukünftige Version der Norm ISO / IEC 9945-2: 1993 dies erfordert {und }einzeln als Steueroperatoren behandelt wird, obwohl das Token {}aufgrund des häufig verwendeten find {}Konstrukts wahrscheinlich eine Sonderfallausnahme davon sein wird .

Diese Notiz wurde in nachfolgenden Versionen des Standards entfernt. Die Beispiele fürfind haben nicht zitierte Verwendungen von {}, wie auch die Beispiele fürxargs . Es mag historische Bourne-Muscheln gegeben haben, in denen {}zitiert werden musste, aber sie wären inzwischen wirklich alte Legacy-Systeme.

Die csh-Implementierungen, die ich zur Hand habe (OpenBSD 4.7, BSD csh unter Debian , tcsh), erweitern sich alle, lassen {foo}sich fooaber in {}Ruhe.

Gilles 'SO - hör auf böse zu sein'
quelle
1
@geekosaur: In Kommentaren funktioniert nur ein kleiner Teil der Abschriften . Ich weiß nicht, was du sagen willst. Wenn es um die Klammererweiterung von ksh et al geht, lesen Sie meinen Abschnitt, der mit "Ksh implementiert die Klammererweiterung als inkompatible Erweiterung" beginnt.
Gilles 'SO- hör auf böse zu sein'
2
Das war bash(siehe $BASH_VERSION). Die Strebenerweiterung ist sehr lebendig und gut.
Geekosaurier
2
Das war der Punkt. Die {}Syntax stammt von csh, wurde jedoch {}auf die leere Zeichenfolge erweitert. Neuere Shells erkennen, dass das unsinnig ist, aber es gibt immer noch einige alte cshs da draußen.
Geekosaurier
1
@geekosaur: Kannst du sagen, welche spezifische csh-Version auf welcher spezifischen Plattform? Ich würde es vorziehen, es selbst zu testen (wenn es unter Linux möglich ist) oder mir sicher sein, dass die Person es selbst testet.
Benutzer unbekannt
1
@geekosaur, {}foowürde erweitern auf foo, {}würde aber erweitern auf {}(außer bei Backticks, aber Zitieren würde nicht helfen) und wurde als solches dokumentiert. Ich habe es für die csh von 2BSD (erste Veröffentlichung), 2.79BSD, 2.8BSD und 2.11BSD verifiziert.
Stéphane Chazelas
12

Das {}musste in Versionen der fishShell vor 3.0.0 zitiert werden .

$ fish -c 'echo find -exec {} \;'
find -exec  ;

Und in der RC-Shell (auch akangabasierend auf rc, aber nicht es):

$ rc -c "echo find -exec {} ';'"
line 1: syntax error near '{'

Das sind wahrscheinlich nicht die Shells, an die die Autoren dieser GNU-Funddokumentation gedacht hatten, als sie diesen Text geschrieben haben, seit er fish2005 zum ersten Mal veröffentlicht wurde (während dieser Text oder ähnliches bereits 1994 da war) und rcursprünglich keine Unix-Shell waren.

Es gibt einige Gerüchte, dass einige Versionen csh(der Shell, die die Klammererweiterung eingeführt hat) dies erfordern. Aber es ist schwer, diese zu würdigen, seitdem die erste Veröffentlichung von cshin 2BSD dies nicht getan hat. Hier, wie in einem PDP11-Emulator getestet:

# echo find -exec {} \;
find -exec {} ;

Und in der Manpage von 2BSD heißt es csheindeutig :

Als Sonderfall werden `{',`}' und `{} 'ungestört übergeben.

Ich würde es sehr seltsam finden, wenn eine nachfolgende Version von csh oder tcsh das später kaputt machen würde.

Es hätte sein können, dass in einigen Versionen einige Fehler behoben wurden. Immer noch mit dieser 2BSD csh (das ist dasselbe in 2.79BSD, 2.8BSD, 2.11BSD):

# csh -x
# echo foo {} bar
echo foo {} bar
foo {} bar
# echo `echo foo {} bar`
echo `echo foo {} bar`
echo foo {} bar
foo  bar

Das Zitieren hilft jedoch nicht:

# echo `echo foo '{}' bar`
echo `echo foo '{}' bar`
echo foo {} bar
foo  bar

Sie könnten die gesamte Befehlsersetzung zitieren:

# echo "`echo foo {} bar`"
echo `echo foo {} bar`
echo foo {} bar
foo {} bar

Aber das ist ein Argument für dieses äußere Echo.

In cshoder tcshmüsstest du das zitieren, {}wenn es nicht alleine ist wie in:

find . -name '*.txt' -type f -exec cp {} '{}.back' \;

(obwohl diese Art der findNutzung nicht portabel ist, da einige finds nur erweitert werden, {}wenn sie für sich alleine sind).

Stéphane Chazelas
quelle
1

Mit einem Wort csh. bashund andere moderne Shells erkennen, dass der Benutzer wahrscheinlich nicht nach einer Null-Klammer-Erweiterung fragt. (Modern cshist eigentlich tcshund kann {}mittlerweile auch vernünftig umgehen .)

Geekosaurier
quelle
Schön zu hören, aber ich bitte um das Gegenteil.
Benutzer unbekannt
Sie gehen davon aus, dass jemand den Hinweis auf zusätzliche Zitate auf der Infoseite herausreißt, nur weil alle Linux-Systeme neuer sind csh. Nicht jeder führt GNU-Dienstprogramme unter Linux aus. In der Tat ist es durchaus üblich, sie auf älteren kommerziellen Unix-Systemen zu installieren, deren Befehle begrenzt sind. (Austausch cshauf diesen Systemen ist es weniger wahrscheinlich, weil Systemskripte auf den Eigentümlichkeiten des Originals berufen kann csh, und auch wenn Benutzer alle konfiguriert wurden , ein neuen zu verwenden csh, rootmüßte mit ziemlicher Sicherheit die gebündelte Version bleiben.)
geekosaur
2
Nein. Ich bin in einer Debatte mit einem Typen, der sagt, dass wir in unserem Wiki den Rat geben sollten, die ganze Zeit "{}" zu verwenden, weil die Manpage dies sagt. Und jetzt möchte ich wissen, ob es eine Shell gibt, die ich nicht benutze, wie ksh, zsh, tcsh, csh oder XYZsh, die ich nicht kenne, für die diese Behauptung zutrifft, oder ob ich das ehrlich annehmen kann gibt es nicht. Wenn es Shells für verschiedene Unixe gibt, die das "{}" benötigen, wäre das eine gute Erklärung, warum der Satz noch in der Manpage enthalten ist, aber nicht als Hinweis für Linux-Anfänger geeignet.
Benutzer unbekannt
Jetzt frage ich mich , ob pdkshdas Richtige tut ... obwohl die richtige Antwort auf das wahrscheinlich ist „real kshist FOSS in diesen Tagen“.
Geekosaurier
4
Pdksh erweitert wie mksh, ksh93, bash und zsh nur geschweifte Klammern, wenn ein Komma dazwischen steht (oder ..für ksh93, bash und zsh). Nur (t) csh dehnt {foo}sich aus foound lässt es auch {}alleine (zumindest bei aktuellen BSDs).
Gilles 'SO - hör auf böse zu sein'