Chcę dokładnie wiedzieć, co {} \;
i {} \+
i | xargs ...
zrobić. Prosimy o wyjaśnienie ich wraz z objaśnieniami.
Poniżej 3 polecenia uruchamiają się i wyświetlają ten sam wynik, ale pierwsze polecenie zajmuje trochę czasu, a format jest również trochę inny.
find . -type f -exec file {} \;
find . -type f -exec file {} \+
find . -type f | xargs file
To dlatego, że 1st uruchamia file
polecenie dla każdego pliku pochodzącego z find
polecenia. Więc w zasadzie działa jako:
file file1.txt
file file2.txt
Ale ostatnie 2 znajdź za pomocą -exec
poleceń uruchom polecenie pliku raz dla wszystkich plików, jak poniżej:
file file1.txt file2.txt
Następnie uruchamiam następujące polecenia, na których pierwsza działa bez problemu, a druga wyświetla komunikat o błędzie.
find . -type f -iname '*.cpp' -exec mv {} ./test/ \;
find . -type f -iname '*.cpp' -exec mv {} ./test/ \+ #gives error:find: missing argument to `-exec'
W przypadku polecenia z {} \+
daje mi komunikat o błędzie
find: missing argument to `-exec'
dlaczego? czy ktoś może wyjaśnić, co robię źle?
Odpowiedzi:
Strona podręcznika (lub internetowy podręcznik GNU ) prawie wszystko wyjaśnia.
polecenie find -exec {} \;
Dla każdego wyniku
command {}
jest wykonywany. Wszystkie wystąpienia{}
są zastępowane nazwą pliku.;
jest poprzedzony ukośnikiem, aby zapobiec jego interpretacji przez powłokę.znajdź -exec polecenie {} +
Każdy wynik jest następnie dołączany
command
i wykonywany. Biorąc pod uwagę ograniczenia długości polecenia, myślę, że to polecenie może być wykonywane więcej razy, przy wsparciu strony podręcznika:Zwróć uwagę na ten cytat ze strony podręcznika:
Dlatego żadne znaki nie są dozwolone między
{}
i+
z wyjątkiem białych znaków.+
powoduje, że find wykryje, że argumenty powinny być dołączone do polecenia tak samo, jakxargs
.Rozwiązanie
Na szczęście implementacja GNU
mv
akceptuje katalog docelowy jako argument, z jednym-t
lub dłuższym parametrem--target
. Jego użycie będzie:Twoje
find
polecenie staje się:Ze strony podręcznika:
źródło
./test/
między{}
i+
, ale między nimi nie są dozwolone żadne znaki inne niż białe znaki.+
Komenda jest nieco dziwne AFAIU ponieważ kije pliki na „koniec” (a nie w miejscu{}
), dzięki czemu korzystając{}
w ogóle - jest to mylące. Dzięki za-t
opcję, o której nie wiedziałem, wygląda na to, że opcja została utworzona jako obejście tego-exec +
problemu!Napotkałem ten sam problem na Mac OSX , używając powłoki ZSH : w tym przypadku nie ma
-t
opcjimv
, więc musiałem znaleźć inne rozwiązanie. Jednak następujące polecenie powiodło się:Sekret polegał na zacytowaniu szelek . Nie ma potrzeby, aby klamry znajdowały się na końcu
exec
polecenia.Testowałem pod Ubuntu 14.04 (z powłokami BASH i ZSH ), działa tak samo.
Jednak podczas używania
+
znaku rzeczywiście wydaje się, że musi on znajdować się na końcuexec
polecenia.źródło
{}
musi być cytowany wfish
irc
muszle, ale niezsh
,bash
ani żadnych innych powłok Bourne lub csh rodzin.bash
, rzeczywiście cytaty nie są konieczne. Co ciekawe, miałem problem, jeśli nie cytowałem ich pod MacOS (używajączsh
). Ale nie mam Maca w zasięgu ręki, żeby spróbować ponownie ...Standardowym odpowiednikiem
find -iname ... -exec mv -t dest {} +
dlafind
implementacji, które nie obsługują-iname
lubmv
implementacji, które nie obsługują,-t
jest użycie powłoki do zmiany kolejności argumentów:Używając
-name '*.[cC][pP][pP]'
, unikamy również polegania na bieżących ustawieniach regionalnych przy decydowaniu, jaka jest wersjac
lub wielka literap
.Zauważ, że
+
w przeciwieństwie do;
nie jest wyjątkowy w żadnej powłoce, więc nie musi być cytowany (chociaż cytowanie nie zaszkodzi, z wyjątkiem oczywiście takich powłokrc
, które nie obsługują\
operatora cytowania).Kropka
/
w/dest/dir/
jest tak, żemv
nie powiedzie się z powodu błędu zamiast zmiany nazwyfoo.cpp
do/dest/dir
w przypadku, gdy tylko jedencpp
plik został odnaleziony i/dest/dir
nie istnieje lub nie jest katalogiem (lub dowiązaniem do katalogu).źródło
źródło
nie, różnica między
+
i\;
powinna zostać odwrócona.+
dołącza pliki na koniec polecenia exec, a następnie uruchamia polecenie exec i\;
uruchamia polecenie dla każdego pliku.Problem w tym,
find . -type f -iname '*.cpp' -exec mv {} ./test/ \+
żefind . -type f -iname '*.cpp' -exec mv {} ./test/ +
nie powinno być potrzeby ucieczki lub kończenia rozszerzenia+
xargs, których nie używałem od dłuższego czasu, ale myślę, że działa jak +.
źródło
-name "*.cpp"
ja prawie nie używa -iname chyba że chcesz zrobić trochę trudne szukanie regex, jak -iname '??? pracy * \ CPP..'-iname
i-name
.-iname
jest wersją programu-name
bez rozróżniania wielkości liter i nie ma różnic w obsłudze wyrażeń regularnych. Proponuję wypróbować polecenia przed wysłaniem, twoje polecenie również nie działa w mojej powłoce.