Próbuję uruchomić polecenie podobne do poniższego w skrypcie bash. Powinien przeszukiwać wszystkie podfoldery $sourcedir
i kopiować wszystkie pliki określonego typu na poziom główny $targetdir
.
#!/bin/bash
# These are set as arguments to the script, not hard-coded
sourcedir="/path/to/sourcedir"
targetdir="/path/to/targetdir"
find "$sourcedir" -type f -name "*.type" -exec sh -c 'cp "$1" "$2/`basename "$1"`"' "{}" "$targetdir" \;
To wydaje się być dość blisko, oprócz tego, że {}
nie jest przekazywana jako $2
do-exec sh -c ...
Chciałbym to zrobić tak blisko „właściwej drogi”, jak to możliwe, z tolerancją dla znaków specjalnych w nazwach plików (w szczególności znaków pojedynczego cudzysłowu).
Edycja: widzę ludzi sugerujących użycie xargs
lub tworzenie łańcuchów argumentów. Miałem wrażenie, że jest to w porządku tylko w przypadku ograniczonej liczby argumentów. Jeśli mam na przykład tysiące plików .jpg, które próbuję skopiować z wielu katalogów galerii do gigantycznego katalogu pokazu slajdów, czy rozwiązania łańcuchowe argumentów nadal będą działać?
Edycja 2: Mój problem polegał na tym, że brakowało _
mi przed pierwszą opcją sh w -exec
poleceniu. Dla każdego, kto jest ciekawy, jak sprawić, by polecenie find działało, dodaj _
i wszystko będzie dobrze:
find "$sourcedir" -type f -name "*.type" -exec sh -c 'cp "$1" "$2"' _ "{}" "$targetdir" \;
Przyjąłem odpowiedź poniżej, ponieważ spełnia to samo zadanie, ale jest bardziej wydajne i eleganckie.
źródło
xargs
kiedykolwiek został stworzony, aby automatycznie obsługiwać ogromne ilości argumentów na zwykłych komendach, które miały ograniczenia. Należy również wziąć pod uwagę, że większość maksymalnych limitów argumentów została znacznie ulepszona dla standardowych narzędzi GNU. Zauważysz także poprawę wydajności, unikając wszystkich tych forków procesowych, co w tysiącach plików jest istotne.Odpowiedzi:
Chcesz skopiować pliki określonego typu do określonego katalogu? Najlepiej to zrobić
xargs
i nawet tego nie potrzebujeszsh
. Jest to bardziej odpowiedni sposób, aby to zrobić, powinien również działać bardziej wydajnie.Jeśli potrzebujesz obsługiwać specjalne nazwy plików, użyj ich
NULL
jako separatoraźródło
-print0
dofind
i-0
doxargs
NULL
nie jest konieczne, jeśli używasz'{}'
, jest ważne, gdy nie używasz. Prawdziwą korzyścią między innymi, opróczPOSIX
zgodności, jest wydajność.Musisz przekazać
{}
jako argument do powłoki, a następnie zapętlić każdy argument.Uwaga : W ten sposób pierwszy argument do powłoki jest nazwą powłoki , możemy to wykorzystać, przekazując nazwę jako,
$targetdir
a następnie używając specjalnego parametru$0
w skrypcie powłoki, aby uzyskać dostęp do tego katalogu docelowego.źródło
"$targetdir"
nie jest rozwijany w pojedynczych cudzysłowach.Jeśli nie wierzysz w kościół xargs:
Wyjaśnienie:
kopiuje b, cid do docelowego katalogu a.
wywołuje polecenie na dużej grupie plików jednocześnie, nie jeden po drugim (co jest standardem, jeśli używasz
";"
zamiast+
). Dlatego musisz wyciągnąć katalog docelowy na przód i oznaczyć go jako cel.Działa to dla gnu-find i może nie działać w przypadku innych implementacji find. Oczywiście zależy to również od flagi -t.
TechZilla ma oczywiście rację, ponieważ
sh
nie jest potrzebna do wywołania cp.Jeśli nie używasz
xargs
, co jest w większości przypadków niepotrzebne w połączeniu zfind
, oszczędzasz się od nauki flagi-print0
i-0
.źródło
xargs
. Największy przykład, co jeśli nie znajdziesz plików?for
Cały czas używam xargs zamiast ogólnych pętli,find
ma znacznie mniejszy zakres. Ponadtofind
obsługuje tylko to, że+
jeśli używasz GNUfind
, nie jest to zdefiniowane w POSIX. Więc chociaż powinieneś swobodnie wybieraćfind
samemu, nie robi wszystkiego, co robi xargs. Rozważając GNUxargs
, dostajesz także to,-P
co robi wielordzeniowy.xargs
Niezależnie od tego warto się uczyć .źródło