Ich bin auf Solaris 10 und habe Folgendes mit ksh (88), bash (3.00) und zsh (4.2.1) getestet.
Der folgende Code liefert kein Ergebnis:
function foo {
echo "Hello World"
}
find somedir -exec foo \;
Der Fund hat mehrere Dateien entspricht (wie durch Ersetzen gezeigt -exec ...
mit -print
), und der Funktion funktioniert perfekt , wenn außerhalb von dem gerufenen find
Anruf.
Hier ist, was die man find
Seite sagt -exec
:
-exec Befehl True, wenn der ausgeführte Befehl a zurückgibt Nullwert als Ausgangsstatus. Das Ende von Befehl muss durch ein Escapezeichen unterbrochen werden Semikolon (;). Ein Befehlsargument {} ist ersetzt durch den aktuellen Pfadnamen. Wenn das Das letzte Argument für -exec ist {} und Sie Geben Sie + anstelle des Semikolons (;) an. Der Befehl wird mit weniger Male aufgerufen {} ersetzt durch Gruppen von Pfadnamen. Ob Jeder Aufruf des Befehls gibt a zurück Nicht-Null-Wert als Exit-Status, finden Gibt einen Exit-Status ungleich Null zurück.
Ich könnte wahrscheinlich mit etwas davonkommen:
for f in $(find somedir); do
foo
done
Aber ich habe Angst, mich mit Feldtrennungsproblemen zu befassen.
Ist es möglich, eine Shell-Funktion (definiert im selben Skript, kümmern wir uns nicht um das Scoping) von einem find ... -exec ...
Aufruf aus aufzurufen?
Ich habe es mit beiden /usr/bin/find
und versucht /bin/find
und habe das gleiche Ergebnis erzielt.
export -f foo
PATH
. Alternativ können Sie mitsh -c '...'
und beide definieren UND die Funktion im...
Bit ausführen . Es kann hilfreich sein, die Unterschiede zwischen Funktionen und Skripten zu verstehen .Antworten:
A
function
ist lokal für eine Shell, also brauchst du esfind -exec
eine Shell erzeugen und diese Funktion in dieser Shell definieren, bevor Sie sie verwenden können. So etwas wie:bash
erlaubt es einem, Funktionen über die Umgebung mit zu exportierenexport -f
, so können Sie (in bash):ksh88
hattypeset -fx
Funktion exportieren (nicht über die Umgebung), aber das kann nur von she-bang weniger Skripten ausgeführt werdenksh
, also nicht mitksh -c
.Eine andere Option ist zu tun:
Verwenden Sie
typeset -f
diese Option, um die Definition derfoo
Funktion im Inline-Skript zu sichern. Beachten Sie, dass Sie beifoo
Verwendung anderer Funktionen diese ebenfalls sichern müssen.quelle
ksh
oderbash
in dem-exec
Befehl? Ich verstehe das erste, aber nicht das zweite Vorkommen.bash -c 'some-code' a b c
,$0
ista
,$1
istb
..., wenn Sie so wollen ,$@
um seinea, b, c
Sie benötigen , bevor etwas einzufügen. Da dies$0
auch bei der Anzeige von Fehlermeldungen verwendet wird, ist es eine gute Idee, den Namen der Shell zu verwenden oder etwas, das in diesem Kontext sinnvoll ist.Dies ist nicht immer anwendbar, aber wenn es so ist, ist es eine einfache Lösung. Stellen Sie die
globstar
Option ein (set -o globstar
in ksh93shopt -s globstar
in bash ≥4; in zsh ist sie standardmäßig aktiviert). Verwenden Sie dann**/
, um das aktuelle Verzeichnis und seine Unterverzeichnisse rekursiv abzugleichen.Beispielsweise können Sie statt
find . -name '*.txt' -exec somecommand {} \;
ausführenStattdessen
find . -type d -exec somecommand {} \;
kannst du rennenStattdessen
find . -newer somefile -exec somecommand {} \;
kannst du rennenWenn
**/
es bei Ihnen nicht funktioniert (weil Ihre Shell es nicht hat oder weil Sie einefind
Option benötigen , die kein Shell-Analogon hat), definieren Sie die Funktion imfind -exec
Argument .quelle
globstar
Option für die vonksh88
mir verwendete Version von ksh ( ) finden.dtksh
(Ksh93 mit einigen X11-Erweiterungen), aber eine alte Version und möglicherweise Teil eines optionalen Pakets, in dem CDE optional ist.find
dass es Punktdateien ausschließt und nicht in Punktverzeichnisse abfällt und die Dateiliste sortiert (beides können Adressen in zsh durch Globbing-Qualifizierer sein). Auch mit**/*
im Gegensatz zu./**/*
können Dateinamen mit beginnen-
.Verwenden Sie \ 0 als Trennzeichen und lesen Sie die Dateinamen aus einem erzeugten Befehl in den aktuellen Prozess ein.
Was ist hier los:
read -d ''
Liest bis zum nächsten \ 0 Byte, sodass Sie sich nicht um seltsame Zeichen in Dateinamen kümmern müssen.-print0
wird \ 0 verwendet, um jeden generierten Dateinamen anstelle von \ n zu beenden.cmd2 < <(cmd1)
ist dasselbe wie mit dercmd1 | cmd2
Ausnahme, dass cmd2 in der Haupt-Shell und nicht in einer Subshell ausgeführt wird./dev/null
um sicherzustellen, dass er nicht versehentlich aus der Pipe gelesen wird.$filename
wird in Anführungszeichen gesetzt, damit die Shell nicht versucht, einen Dateinamen zu teilen, der Leerzeichen enthält.Nun,
read -d
und<(...)
sind in zsh, bash und ksh 93u, aber ich bin nicht sicher, was frühere ksh-Versionen angeht.quelle
Wenn Sie möchten, dass ein aus Ihrem Skript stammender untergeordneter Prozess eine vordefinierte Shell-Funktion verwendet, mit der Sie ihn exportieren müssen
export -f <function>
HINWEIS:
export -f
ist bash-spezifischda nur eine Shell Shell- Funktionen ausführen kann:
BEARBEITEN: Im Wesentlichen sollte Ihr Skript so aussehen:
quelle
export -f
ist ein Syntaxfehler inksh
und gibt die Funktionsdefinition auf dem Bildschirm in auszsh
. In allenksh
,zsh
undbash
, löst es das Problem nicht.find / -exec /bin/bash -c 'function' \;
bash
. Vielen Dank!{}
in den Shell-Code einbetten ! Das heißt, der Dateiname wird als Shell-Code interpretiert und ist daher sehr gefährlich