Korzystam z systemu Solaris 10 i przetestowałem następujące opcje z ksh (88), bash (3.00) i zsh (4.2.1).
Poniższy kod nie daje żadnego wyniku:
function foo {
echo "Hello World"
}
find somedir -exec foo \;
Znalezisko pasuje kilka plików (jak pokazano poprzez zastąpienie -exec ...
z -print
), a funkcja działa idealnie, kiedy nazywa zewnątrz od find
połączenia.
Oto, co man find
mówi strona -exec
:
-exec polecenie Prawda, jeśli wykonane polecenie zwraca a zero wartości jako status wyjścia. Koniec polecenie musi być przerywane znakiem ucieczki średnik (;). Argumentem polecenia {} jest zastąpiony bieżącą nazwą ścieżki. Jeśli… ostatnim argumentem dla -exec jest {} a ty podaj + zamiast średnika (;), polecenie jest wywoływane mniej razy, przy pomocy {} zastąpiono grupami ścieżek. Jeśli każde wywołanie polecenia zwraca a wartość niezerowa jako status wyjścia, znajdź zwraca niezerowy status wyjścia.
Prawdopodobnie mógłbym uciec, robiąc coś takiego:
for f in $(find somedir); do
foo
done
Ale boję się rozwiązywać problemy z separatorem pól.
Czy można wywołać funkcję powłoki (zdefiniowaną w tym samym skrypcie, nie zawracajmy sobie głowy problemami z zakresu) z find ... -exec ...
wywołania?
Próbowałem zarówno /usr/bin/find
i /bin/find
otrzymał ten sam wynik.
export -f foo
PATH
. Alternatywnie użyjsh -c '...'
i zdefiniuj ORAZ uruchom funkcję w...
bicie. Może pomóc zrozumieć różnice między funkcjami a skryptami .Odpowiedzi:
A
function
jest lokalne dla powłoki, więc musiszfind -exec
móc spawnować powłokę i mieć zdefiniowaną funkcję w tej powłoce, zanim będziesz mógł z niej korzystać. Coś jak:bash
pozwala eksportować funkcje za pomocą środowiskaexport -f
, dzięki czemu możesz (bash):ksh88
musitypeset -fx
wyeksportować funkcję (nie przez środowisko), ale może być używana tylko przez skrypty wykonujące mniej she-bangksh
, więc nie zksh -c
.Inną opcją jest wykonanie:
To znaczy, użyj,
typeset -f
aby zrzucić definicjęfoo
funkcji w skrypcie wbudowanym. Pamiętaj, że jeślifoo
używasz innych funkcji, musisz je również zrzucić.źródło
ksh
lubbash
w-exec
poleceniu? Rozumiem pierwsze, ale nie drugie wystąpienie.bash -c 'some-code' a b c
,$0
isa
,$1
isb
..., więc jeśli chcesz$@
byća, b, c
, musisz coś wcześniej wstawić. Ponieważ$0
jest również używany podczas wyświetlania komunikatów o błędach, dobrym pomysłem jest użycie nazwy powłoki lub czegoś, co ma sens w tym kontekście.Nie zawsze ma to zastosowanie, ale kiedy jest, jest to proste rozwiązanie. Ustaw
globstar
opcję (set -o globstar
w ksh93,shopt -s globstar
w bash ≥4; jest domyślnie włączony w zsh). Następnie użyj,**/
aby rekurencyjnie dopasować bieżący katalog i jego podkatalogi.Na przykład zamiast
find . -name '*.txt' -exec somecommand {} \;
można uruchomićZamiast tego
find . -type d -exec somecommand {} \;
możesz biegaćZamiast tego
find . -newer somefile -exec somecommand {} \;
możesz biegaćKiedy
**/
nie działa dla ciebie (ponieważ twoja powłoka go nie ma lub potrzebujeszfind
opcji, która nie ma analogu powłoki), zdefiniuj funkcję wfind -exec
argumencie .źródło
globstar
opcji w używanej przezeksh88
mnie wersji ksh ( ).dtksh
(ksh93 z niektórymi rozszerzeniami X11), ale starą wersję i być może część opcjonalnego pakietu, w którym CDE jest opcjonalny.find
tym, że wyklucza pliki kropkowe i nie schodzi na kropki i że sortuje listę plików (oba mogą być adresami w zsh poprzez kwalifikatory globowania). Również**/*
w przeciwieństwie do./**/*
, nazwy plików mogą zaczynać się od-
.Użyj \ 0 jako separatora i odczytaj nazwy plików w bieżącym procesie z polecenia spawnowanego, tak jak poniżej:
Co tu się dzieje:
read -d ''
czyta do następnego bajtu \ 0, więc nie musisz się martwić o dziwne znaki w nazwach plików.-print0
używa \ 0 do zakończenia każdej wygenerowanej nazwy pliku zamiast \ n.cmd2 < <(cmd1)
jest taki sam,cmd1 | cmd2
z wyjątkiem tego, że cmd2 jest uruchamiany w głównej powłoce, a nie w podpowłoce./dev/null
aby upewnić się, że nie odczytuje przypadkowo z potoku.$filename
jest cytowany, aby powłoka nie próbowała podzielić nazwy pliku zawierającej spacje.Teraz,
read -d
i<(...)
są w zsh, bash i ksh 93u, ale nie jestem pewien co do wcześniejszych wersji ksh.źródło
jeśli chcesz, aby proces potomny, spawnowany ze skryptu, używał wstępnie zdefiniowanej funkcji powłoki, z którą musisz ją wyeksportować
export -f <function>
UWAGA:
export -f
jest specyficzny dla bashponieważ tylko powłoka może uruchamiać funkcje powłoki :
EDYCJA: zasadniczo twój skrypt powinien przypominać to:
źródło
export -f
jest błędem składni wksh
i drukuje definicję funkcji na ekranie wzsh
. We wszystkichksh
,zsh
ibash
to nie rozwiązuje problemu.find / -exec /bin/bash -c 'function' \;
bash
. Dziękuję Ci!{}
w kodzie powłoki! Oznacza to, że nazwa pliku jest interpretowana jako kod powłoki, więc jest bardzo niebezpieczny