find-exec a shell function in Linux?
Czy istnieje sposób, aby find
wykonać funkcję, którą zdefiniuję 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 Jest jakiś sposób, aby find
' S -exec
zobaczyć dosomething
?
12 answers
Ponieważ tylko powłoka wie, jak uruchamiać funkcje powłoki, musisz uruchomić powłokę, aby uruchomić funkcję. Musisz również oznaczyć funkcję do eksportu export -f
, w przeciwnym razie subshell nie odziedziczy ich:
export -f dosomething
find . -exec bash -c 'dosomething "$0"' {} \;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-22 05:13:58
find . | while read file; do dosomething "$file"; done
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-13 12:39:32
Dodaj cytaty w {[1] } Jak pokazano poniżej:
export -f dosomething
find . -exec bash -c 'dosomething "{}"' \;
To koryguje wszelkie błędy spowodowane znakami specjalnymi zwracanymi przez find
,
na przykład pliki z nawiasami w nazwie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-16 02:29:20
Odpowiedź jak powyżej jest świetna, ale ma kilka pułapek, które można łatwo pokonać:
find . -print0 | while IFS= read -r -d '' file; do dosomething "$file"; done
To używa null jako ogranicznika zamiast linefeed, więc nazwy plików z linefeeds będą działać. Używa również znacznika -r
, który wyłącza unikanie ukośników wstecznych, bez niego ukośniki w nazwach plików nie będą działać. Czyści również IFS
, aby potencjalne końcowe spacje w nazwach nie były odrzucane.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-13 21:55:22
Wykonaj samo wywołanie skryptu, przekazując każdy znaleziony element jako argument:
#!/bin/bash
if [ ! $1 == "" ] ; then
echo "doing something with $1"
exit 0
fi
find . -exec $0 {} \;
exit 0
Gdy uruchomisz skrypt samodzielnie, znajdzie to, czego szukasz i wywoła się z każdego wyniku wyszukiwania jako argumentu. Gdy skrypt jest uruchamiany z argumentem, wykonuje polecenia na argumencie, a następnie kończy działanie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-22 18:10:38
Wyniki przetwarzania luzem
W celu zwiększenia wydajności, Wiele osób używaxargs
do przetwarzania wyników luzem, ale jest to bardzo niebezpieczne. Z tego powodu do find
została wprowadzona alternatywna metoda, która wykonuje wyniki masowo.
Zauważ jednak, że ta metoda może zawierać pewne zastrzeżenia, takie jak na przykład wymóg w POSIX-find
, aby mieć {}
na końcu polecenia.
export -f dosomething
find . -exec bash -c 'for f; do dosomething "$f"; done' _ {} +
find
przekazuje wiele wyników jako argumenty do jednego wywołania bash
i for
- pętla iteruje przez te argumenty, wykonując funkcję dosomething
na każdym z nich.
Powyższe rozwiązanie rozpoczyna argumenty od $1
, dlatego istnieje _
(która reprezentuje $0
).
Wyniki przetwarzania jeden po drugim
W ten sam sposób, myślę, że przyjęta odpowiedź powinna być poprawiona
export -f dosomething
find . -exec bash -c 'dosomething "$1"' _ {} \;
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 nieoczekiwane zachowanie, jeśli nazwa pliku zwracana przez find
ma specjalne znaczenie dla powłoki.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-08 18:33:00
Dla tych z Was, którzy szukają funkcji bash, która wykona daną komendę na wszystkich plikach w bieżącym katalogu, skompilowałem jedną z powyższych odpowiedzi:
toall(){
find . -type f | while read file; do "$1" "$file"; done
}
Zauważ, że łamie się z nazwami plików zawierającymi spacje (patrz poniżej).
Jako przykład, weźmy tę funkcję:
world(){
sed -i 's_hello_world_g' "$1"
}
Powiedzmy, że chciałem zmienić wszystkie instancje hello to world we wszystkich plikach w bieżącym katalogu. Zrobiłbym:
toall world
Aby być bezpiecznym z dowolnymi symbolami w nazwach plików, użyj:
toall(){
find . -type f -print0 | while IFS= read -r -d '' file; do "$1" "$file"; done
}
(ale potrzebujesz find
, który obsługuje -print0
np. GNU find
).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-09 17:54:51
Nie jest możliwe wykonanie funkcji w ten sposób.
Aby to przezwyciężyć, możesz umieścić swoją funkcję w skrypcie powłoki i wywołać ją z find
# dosomething.sh
dosomething () {
echo "doing something with $1"
}
dosomething $1
Teraz użyj go w find jako:
find . -exec dosomething.sh {} \;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-01 05:29:00
Umieść funkcję w osobnym pliku i get find
, aby ją wykonać.
Funkcje powłoki są wewnętrzne do powłoki, w której są zdefiniowane; find
nigdy nie będą w stanie ich zobaczyć.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-01 05:29:14
Znajduję najprostszy sposób jak poniżej, powtarzając dwa polecenia w jednym do
func_one () {
echo "first thing with $1"
}
func_two () {
echo "second thing with $1"
}
find . -type f | while read file; do func_one $file; func_two $file; done
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-07 09:12:02
Nie bezpośrednio, nie. Find jest wykonywany 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.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-01 05:27:57
W ogóle nie używałbym -exec
. Dlaczego nie użyć xargs
?
find . -name <script/command you're searching for> | xargs bash -c
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-11 22:16:21