Czy istnieje sposób na find
wykonanie funkcji zdefiniowanej w powłoce? Na przykład:
dosomething () {
echo "doing something with $1"
}
find . -exec dosomething {} \;
Wynikiem tego jest:
find: dosomething: No such file or directory
Czy istnieje sposób, aby uzyskać find
„S -exec
zobaczyć dosomething
?
$0
.find . -exec bash -c 'dosomething "$0"' {} \;
go użyjesz , będzie on obsługiwał spacje (i inne dziwne znaki) w nazwach plików ...export -f
Będzie działać tylko w niektórych wersjach bash. To nie jest posix, nie crossplatforn,/bin/sh
będzie miał z tym błądźródło
while read
się na pętlę for;for item in $(find . ); do some_function "${item}"; done
Powyższa odpowiedź Jaka jest świetna, ale ma kilka pułapek, które można łatwo pokonać:
Używa wartości null jako separatora zamiast kanału, więc nazwy plików z kanałami będą działać. Używa także
-r
flagi, która wyłącza ucieczkę ukośnika odwrotnego, bez tego ukośniki w nazwach plików nie będą działać. Usuwa się równieżIFS
, aby potencjalne końcowe spacje w nazwach nie były odrzucane.źródło
/bin/bash
ale nie działa/bin/sh
. Jaka szkoda.Dodaj cytaty,
{}
jak pokazano poniżej:To koryguje wszelkie błędy spowodowane przez znaki specjalne zwracane przez
find
, na przykład pliki z nawiasami w nazwie.źródło
{}
. Spowoduje to uszkodzenie pliku zawierającego podwójne cudzysłowy.touch '"; rm -rf .; echo "I deleted all you files, haha
. Ups-exec bash -c 'echo $0' '{}' \;
Zauważ, że podczas używaniabash -c
$ 0 jest pierwszym argumentem, a nie nazwą skryptu.Przetwarzanie wyników luzem
Aby zwiększyć wydajność, wiele osób używa
xargs
do przetwarzania wyników luzem, ale jest to bardzo niebezpieczne. Z tego powodu wprowadzono alternatywną metodę,find
która wykonuje wyniki masowo.Zauważ jednak, że ta metoda może zawierać pewne zastrzeżenia, takie jak na przykład wymóg POSIX-,
find
aby mieć{}
na końcu polecenia.find
przekaże wiele wyników jako argumenty do pojedynczego wywołaniabash
ifor
pętla iteruje te argumenty, wykonując funkcjędosomething
na każdym z nich.Powyższe rozwiązanie rozpoczyna argumenty od
$1
, i dlatego istnieje_
(który reprezentuje$0
).Przetwarzanie wyników jeden po drugim
W ten sam sposób uważam, że należy poprawić przyjętą najwyższą odpowiedź
Jest to nie tylko bardziej rozsądne, ponieważ argumenty powinny zawsze zaczynać się od
$1
, ale także użycie$0
może prowadzić do nieoczekiwanego zachowania, jeśli nazwa pliku zwrócona przezfind
ma specjalne znaczenie dla powłoki.źródło
Niech skrypt sam się wywołuje, przekazując każdy znaleziony element jako argument:
Po uruchomieniu skryptu sam znajduje to, czego szukasz, i nazywa się, przekazując każdy wynik znalezienia jako argument. Kiedy skrypt jest uruchamiany z argumentem, wykonuje polecenia na argumencie, a następnie kończy działanie.
źródło
find: ‘myscript.sh’: No such file or directory
jeśli zacznie się jakobash myscript.sh
...Dla tych z Was, którzy szukają funkcji bash, która wykona dane polecenie na wszystkich plikach w bieżącym katalogu, skompilowałem jedną z powyższych odpowiedzi:
Zauważ, że łamie się w nazwach plików zawierających spacje (patrz poniżej).
Jako przykład weź tę funkcję:
Powiedzmy, że chciałem zmienić wszystkie wystąpienia hello na world we wszystkich plikach w bieżącym katalogu. Chciałbym zrobić:
Aby być bezpiecznym z dowolnymi symbolami w nazwach plików, użyj:
(ale potrzebujesz takiego,
find
który obsługuje-print0
np. GNUfind
).źródło
Najłatwiej znajduję się w następujący sposób, powtarzając dwa polecenia w jednym do
źródło
Dla porównania unikam tego scenariusza, używając:
Pobierz wyjście z find w bieżącym pliku skryptu i iteruj po wyjściu, jak chcesz. Zgadzam się z zaakceptowaną odpowiedzią, ale nie chcę ujawniać funkcji poza moim plikiem skryptu.
źródło
Wykonywanie funkcji w ten sposób nie jest możliwe .
Aby temu zaradzić, możesz umieścić swoją funkcję w skrypcie powłoki i wywołać ją z
find
Teraz użyj go w find jako:
źródło
dosomething $1
=>dosomething "$1"
i poprawnie uruchomić plik za pomocąfind . -exec bash dosomething.sh {} \;
Umieść funkcję w osobnym pliku i
find
uruchom ją.Funkcje powłoki są wewnętrzne względem powłoki, w której są zdefiniowane;
find
nigdy ich nie zobaczy.źródło
Aby zapewnić uzupełnienia i wyjaśnienia niektórych innych odpowiedzi, jeśli używasz opcji zbiorczej dla
exec
lubexecdir
(-exec command {} +
) i chcesz odzyskać wszystkie argumenty pozycyjne, musisz rozważyć obsługę$0
zbash -c
. Mówiąc bardziej konkretnie, rozważ poniższe polecenie, które używabash -c
jak zasugerowano powyżej, i po prostu wyświetla ścieżki plików kończące się na „.wav” z każdego znalezionego katalogu:Podręcznik bash mówi:
Oto
'check $@'
ciąg polecenia i_ {}
argumenty występujące po nim. Zauważ, że$@
jest to specjalny parametr pozycyjny w bash, który rozszerza się na wszystkie parametry pozycyjne, zaczynając od 1 . Zauważ również, że przy tej-c
opcji pierwszy argument jest przypisywany do parametru pozycyjnego$0
. Oznacza to, że jeśli spróbujesz uzyskać dostęp do wszystkich parametrów pozycyjnych za pomocą$@
, otrzymasz parametry tylko od początku$1
do góry. Dlatego odpowiedź Dominika zawiera_
argument, który jest fikcyjnym argumentem służącym do wypełnienia parametru$0
, więc wszystkie argumenty, które chcemy, będą dostępne później, jeśli użyjemy$@
na przykład rozszerzenia parametrów lub pętli for jak w tej odpowiedzi.Oczywiście, podobnie jak w przypadku zaakceptowanej odpowiedzi,
bash -c 'shell_function $0 $@'
działałby również jawnie$0
, ale trzeba pamiętać, że$@
nie będzie działać zgodnie z oczekiwaniami.źródło
Nie bezpośrednio, nie. Find wykonuje się w osobnym procesie, a nie w powłoce.
Utwórz skrypt powłoki, który wykonuje to samo zadanie co twoja funkcja, i znajdź
-exec
to.źródło
Unikałbym używania
-exec
całkowicie. Dlaczego nie użyćxargs
?źródło