Właśnie zadałem pytanie dotyczące sposobu liczenia plików o określonym rozszerzeniu. Teraz chcę cp
te pliki do nowego dir
.
Próbuję,
cp *.prj ../prjshp/
i
cp * | grep '\.prj$' ../prjshp/
ale dają ten sam błąd,
bash: / bin / cp: lista argumentów za długa
Jak je skopiować?
command-line
files
Sam007
źródło
źródło
Odpowiedzi:
cp *.prj ../prjshp/
jest właściwym poleceniem, ale trafiłeś na rzadki przypadek, w którym dochodzi do ograniczenia rozmiaru. Drugie wypróbowane polecenie nie ma sensu.Jedną z metod jest uruchamianie
cp
plików w porcjach.find
Polecenia wie, jak to zrobić:find
przegląda rekursywnie bieżący katalog i znajdujące się pod nim katalogi.-maxdepth 1
oznacza zatrzymanie się na głębokości 1, tzn. nie wskakuj do podkatalogów.-name '*.prj'
oznacza działanie tylko na plikach, których nazwa pasuje do określonego wzorca. Zwróć uwagę na cytaty wokół wzoru: zostanie zinterpretowany przezfind
polecenie, a nie przez powłokę.-exec … {} +
oznacza wykonanie określonej komendy dla wszystkich plików. W razie potrzeby wywołuje polecenie wiele razy, uważając, aby nie przekroczyć limitu wiersza poleceń.mv -t ../prjshp
przenosi określone pliki do../prjshp
.-t
Opcja jest tutaj stosowane ze względu na ograniczeniafind
komendy: znalezione pliki (symbolizowane przez{}
) są przekazywane jako ostatni argument polecenia, nie można dodać odbiorcę po niej.Inną metodą jest użycie
rsync
.rsync -r … . ../prjshp
kopiuje bieżący katalog do../prjshp
rekurencyjnie.--include='*.prj' --exclude='*'
oznacza kopiowanie pasujących plików*.prj
i wykluczanie wszystkiego innego (w tym podkatalogów, aby.prj
pliki w podkatalogach nie zostały znalezione).źródło
cp * | grep '\.prj$' ../prjshp/
nie ma żadnego sensu, ale może być poprawne pod względem składniowym, jeśli*
rozwija się do listy plików, a ostatni to katalog (akacp SOURCE1 SOURCE2....DEST
). Potok nie ma żadnego sensu, oczywiście, ale pozostaje poprawny pod względem składniowym, jeśli chodzi o powłokę - dobrze zrobidup()
deskryptory plików, po prostu koniec potoku czytnika nie otrzyma żadnych danych, ponieważcp
nie zapisuje żadnych .To polecenie kopiuje pliki jeden po drugim i będzie działać, nawet jeśli jest ich zbyt wiele, aby można je
*
było przekształcić w jednocp
polecenie:źródło
W obliczu
Argument list too long
błędu należy pamiętać o 3 kluczowych kwestiach :Długość argumentów wiersza poleceń jest ograniczona
ARG_MAX
zmienną, która według definicji POSIX to „... [m] maksymalna długość argumentu dla funkcji exec, w tym danych środowiska” (podkreślenie dodane) ”. To znaczy, gdy powłoka wykonuje polecenie inne niż -buduj-to polecenie, musi wywołać jedno z nich,exec()
aby spawnować proces tego polecenia, i to właśnie tamARG_MAX
wchodzi w grę. Dodatkowo, nazwa lub ścieżka do samego polecenia (na przykład/bin/echo
) odgrywa rolę.Wbudowane polecenia powłoki są wykonywane przez powłokę, co oznacza, że powłoka nie korzysta z
exec()
rodziny funkcji i dlategoARG_MAX
zmienna nie ma na nią wpływu .Niektóre polecenia, takie jak
xargs
i,find
są świadomeARG_MAX
zmiennych i wielokrotnie wykonują czynności poniżej tego limituZ powyższych punktów i jak pokazano w doskonałej odpowiedzi Kusalanandy na powiązane pytanie,
Argument list too long
może to również nastąpić, gdy środowisko jest duże. Biorąc pod uwagę, że środowisko każdego użytkownika może się różnić, a wielkość argumentu w bajtach jest istotna, trudno jest wymyślić jedną liczbę plików / argumentów.Jak poradzić sobie z takim błędem?
Najważniejsze jest, aby nie skupiać się na liczbie plików, ale skupić się na tym, czy polecenie, którego zamierzasz użyć, obejmuje
exec()
rodzinę funkcji, a stycznie - przestrzeń stosu.Użyj wbudowanych powłok
Jak wspomniano wcześniej, wbudowane powłoki są odporne na
ARG_MAX
ograniczenia, to znaczy takie jakfor
pętla,while
pętla, wbudowaneecho
i wbudowaneprintf
- wszystkie te będą działać wystarczająco dobrze.Na pokrewne pytanie dotyczące usuwania plików istniało takie rozwiązanie:
Zauważ, że używa to wbudowanej powłoki
printf
. Jeśli dzwonimy do zewnętrznegoprintf
, będzie się to wiązaćexec()
, a zatem nie powiedzie się z dużą liczbą argumentów:tablice bash
Zgodnie z odpowiedzią jlliagre,
bash
nie nakłada ograniczeń na tablice, więc można również budować tablicę nazw plików i używać wycinków na iterację pętli, jak pokazano w odpowiedzi danjprerona :Ogranicza to jednak specyficzność bash i brak POSIX.
Zwiększ przestrzeń stosu
Czasami można zobaczyć ludzi sugerują, zwiększając przestrzeń stosu z
ulimit -s <NUM>
; w systemie Linux wartość ARG_MAX wynosi 1/4 miejsca na stosie dla każdego programu, co oznacza, że zwiększenie miejsca na stosie proporcjonalnie zwiększa miejsce na argumenty.Zgodnie z odpowiedzią Francka Dernoncourta , która cytuje Linux Journal, można również ponownie skompilować jądro Linuksa z większą wartością dla maksymalnej liczby stron pamięci dla argumentów, jednak jest to więcej pracy niż to konieczne i otwiera potencjał dla exploitów, jak stwierdzono w cytowanym artykule Linux Journal.
Unikaj muszli
Innym sposobem jest użycie
python
lubpython3
które są domyślnie dostarczane z Ubuntu. Poniższy przykład Python + tutaj-doc jest czymś, czego osobiście użyłem do skopiowania dużego katalogu plików gdzieś w zakresie 40 000 pozycji:Do przechodzenia rekurencyjnego możesz użyć os.walk .
Zobacz też:
źródło
IMHO, optymalnymi narzędziami do radzenia sobie z hordami plików są
find
ixargs
. Zobaczyćman find
. Zobaczyćman xargs
.find
, z jego-print0
przełącznikiem, tworzy rozdzielonąNUL
listę nazw plików (nazwy plików mogą zawierać dowolny znak execptNUL
lub/
), któryxargs
rozumie, używając-0
przełącznika.xargs
następnie buduje najdłuższe dozwolone polecenie (najwięcej nazw plików, bez połowy nazwy pliku na końcu) i wykonuje je.xargs
powtarza to, dopókifind
nie poda więcej nazw plików. Uruchom,xargs --show-limits </dev/null
aby zobaczyć limity.Aby rozwiązać problem (i po sprawdzeniu,
man cp
aby znaleźć--target-directory=
):źródło