"Peter J. Holzer" <
hjp-u...@hjp.at>:
> On 2023-06-20 10:16, Marco Moock <
mo...@posteo.de> wrote:
>> Ich schaffe es nicht, mehrfach den gefundenen Dateinamen zu
>> verwenden.
>>
>>
>> find -name "xx*" -exec head -n 1 {} > {}-create \;
>> resultiert in einer einzigen Datei namens {}-create.
>>
>> Wie kann ich erreichen, dass die find-Funktion {} mehrfach genutzt
>> werden kann?
>>
>
> Du musst von find aus eine Shell aufrufen:
>
Ja, aber nicht so:
> find -name "xx*" -exec sh -c 'head -n 1 {} > {}-create' \;
Sondern so:
find -name 'xx*' \
-exec sh -c 'head -n 1 "$1" > "$1"-create' sh '{}' \;
Den Grund sieht man an folgendem Beispiel, in einem leeren
Verzeichnis ausgeführt:
# Zuerst werden besondere Dateinamen erzeugt:
touch -- Apostroph\' Anfuehrungszeichen\" Backslash\\ &&
# Dann wird find darauf losgelassen:
find . -exec sh -c -- 'ls -dF -- {}' \;
Das aufgerufene Shell scheitert mit der an ihn übergebenen
Kommandozeile, weil „find“ den gefundenen Dateinamen jeweils
unverändert in die Kommandozeile spuckt, ohne Rücksicht darauf,
dass im Dateinamen Zeichen enthalten sind, die vor dem
Kommandozeilen‐Parser des aufgerufenen Shells geschützt werden
müssen. Und das tut „find“ deshalb so rücksichtslos, weil es
nicht weiß – denn es kann es nicht wissen –, dass die gefundenen
Dateinamen hier in eine „sh“‐Kommandozeile gespuckt werden und
deshalb zuerst mit einem entprechenden Quoting versehen werden
müssten. Deshalb kann man in „find“ so ein Quoting für das Shell
auch nicht einbauen.
Gegenprobe: Das folgende Kommando wird funktionieren:
find . -exec sh -c -- 'ls -dF -- "$@"' sh '{}' \;
Und zwar funktioniert es deshalb, weil die gefundenen Dateinamen
hier nicht in eine Shell‐Kommandozeile gespuckt, sondern dem
Shell als positional parameters übergeben werden. Deshalb kann
das von „find“ gestartete Shell darauf über „"$@"“ zugreifen.
(In diesem Fall ist es immer genau ein Parameter, deshalb könnte
man in der Kommandozeile statt „"$@"“ auch „"$1"“ schreiben.)
Es läuft hier und immer wieder an vielen anderen Stellen darauf
hinaus: Wer mit dem Shell fortgeschritten umgehen will, muss die
richtige Verwendung der Shell‐Option „-c“ beherrschen. Und die
sieht idealerweise so aus:
sh -c -- 'hier kommt eine Kommandozeile ohne variable Teile' \
sh Hier kommen die positional parameters, gerne variabel.
Es kann auch Fälle geben, in denen man nicht darum herum kommt,
dem Shell eine variable, also vom Aufrufer zur Laufzeit zu
bestimmende Kommandozeile zu übergeben. Dann muss man allerdings
die variablen Teile so mit Shell‐Quoting‐Mechanismen („''“, „""“
und „\“) bearbeiten, ehe man sie in die Kommandozeile spuckt,
dass sie für den Kommandozeilen‐Parser des aufgerufenen Shells
passen. Leider stellt der POSIX‐Standard dafür (noch) nichts zur
Verfügung. (Das ins „bash“ eingebaute „printf“‐Kommando und auch
GNU‐printf halten dafür das Formatierungselement „%q“ bereit.)
--
Hat man erst verstanden, wie Unix funktioniert, ist auch
das Shell-Handbuch kein Buch mit sieben Siegeln mehr.