Zuerst, um triviale, aber nicht zutreffende Antworten abzuschneiden: Ich kann weder den find
+ xargs
Trick noch seine Varianten (wie find
bei -exec
) verwenden, da ich pro Aufruf nur wenige solcher Ausdrücke verwenden muss. Ich werde am Ende darauf zurückkommen.
Betrachten wir nun für ein besseres Beispiel:
$ find -L some/dir -name \*.abc | sort
some/dir/1.abc
some/dir/2.abc
some/dir/a space.abc
Wie gebe ich diese als Argumente weiter program
?
Nur das zu tun, reicht nicht aus
$ ./program $(find -L some/dir -name \*.abc | sort)
schlägt fehl, da program
folgende Argumente abgerufen werden:
[0]: ./program
[1]: some/dir/1.abc
[2]: some/dir/2.abc
[3]: some/dir/a
[4]: space.abc
Wie zu sehen ist, wurde der Pfad mit dem Leerzeichen aufgeteilt und program
betrachtet ihn als zwei verschiedene Argumente.
Zitieren, bis es funktioniert
Es scheint, dass Anfänger wie ich, wenn sie mit solchen Problemen konfrontiert sind, dazu neigen, zufällig Anführungszeichen hinzuzufügen, bis es schließlich funktioniert - nur hier scheint es nicht zu helfen ...
"$(…)"
$ ./program "$(find -L some/dir -name \*.abc | sort)"
[0]: ./program
[1]: some/dir/1.abc
some/dir/2.abc
some/dir/a space.abc
Da die Anführungszeichen das Aufteilen von Wörtern verhindern, werden alle Dateien als einzelnes Argument übergeben.
Einzelne Pfade zitieren
Ein vielversprechender Ansatz:
$ ./program $(find -L some/dir -name \*.abc -printf '"%p"\n' | sort)
[1]: "some/dir/1.abc"
[2]: "some/dir/2.abc"
[3]: "some/dir/a
[4]: space.abc"
Die Zitate sind da, klar. Sie werden aber nicht mehr interpretiert. Sie sind nur ein Teil der Saiten. Sie haben also nicht nur die Wortteilung nicht verhindert, sondern auch Streitigkeiten geführt!
IFS ändern
Dann habe ich versucht, damit herumzuspielen IFS
. Ich würde es sowieso find
mit -print0
und sort
mit bevorzugen -z
- damit sie selbst keine Probleme mit "verdrahteten Pfaden" haben. Warum also nicht dem null
Charakter die Wortteilung aufzwingen und alles haben?
$ ./program $(IFS=$'\0' find -L some/dir -name \*.abc -print0 | sort -z)
[0]: ./program
[1]: some/dir/1.abcsome/dir/2.abcsome/dir/a
[2]: space.abc
Es teilt sich also immer noch im Raum und nicht im null
.
Ich habe versucht, die IFS
Aufgabe sowohl in $(…)
(wie oben gezeigt) als auch zuvor zu platzieren ./program
. Auch habe ich versucht , andere Syntax wie \0
, \x0
, \x00
beide zitiert mit '
und "
sowie mit und ohne $
. Keiner von diesen schien einen Unterschied zu machen ...
Und hier habe ich keine Ideen mehr. Ich habe noch ein paar Dinge ausprobiert, aber alle schienen auf die gleichen Probleme wie die aufgelisteten zurückzuführen zu sein.
Was könnte ich noch tun? Ist es überhaupt machbar?
Klar, ich könnte program
die Muster akzeptieren lassen und selbst suchen. Aber es ist eine Menge Doppelarbeit, wenn man es auf eine bestimmte Syntax fixiert. (Was ist grep
zum Beispiel mit der Bereitstellung von Dateien durch a ?)
Außerdem könnte ich das program
Akzeptieren einer Datei mit einer Liste von Pfaden veranlassen. Dann kann ich den find
Ausdruck einfach in eine temporäre Datei kopieren und nur den Pfad zu dieser Datei angeben. Dies kann auf direkten Pfaden unterstützt werden, sodass Benutzer, die nur einen einfachen Pfad haben, diese ohne Zwischendatei bereitstellen können. Aber das scheint nicht schön zu sein - man muss zusätzliche Dateien erstellen und sich um sie kümmern, ganz zu schweigen von der zusätzlichen Implementierung. (Auf der positiven Seite könnte dies jedoch eine Rettung für Fälle sein, in denen die Anzahl der Dateien als Argumente Probleme mit der Befehlszeilenlänge verursacht…)
Lassen Sie mich am Ende noch einmal daran erinnern, dass find
+ xargs
(und ähnliche) Tricks in meinem Fall nicht funktionieren. Zur Vereinfachung der Beschreibung zeige ich nur ein Argument. Aber mein wahrer Fall sieht eher so aus:
$ ABC_FILES=$(find -L some/dir -name \*.abc | sort)
$ XYZ_FILES=$(find -L other/dir -name \*.xyz | sort)
$ ./program --abc-files $ABC_FILES --xyz-files $XYZ_FILES
Wenn ich also xargs
von einer Suche aus mache, habe ich immer noch die Frage, wie ich mit der anderen umgehen soll ...
mapfile
(oder sein Synonymreadarray
). Aber es funktioniert!