Mam folder z ponad milionem plików, który wymaga sortowania, ale tak naprawdę nie mogę nic zrobić, ponieważ mv
cały czas wyświetla ten komunikat
-bash: /bin/mv: Argument list too long
Używam tego polecenia do przenoszenia plików bez rozszerzeń:
mv -- !(*.jpg|*.png|*.bmp) targetdir/
Odpowiedzi:
xargs
jest narzędziem do pracy. To lubfind
z-exec … {} +
. Te narzędzia uruchamiają polecenie kilka razy, z tyloma argumentami, ile można przekazać za jednym razem.Obie metody są łatwiejsze do przeprowadzenia, gdy lista argumentów zmiennych znajduje się na końcu, co nie ma miejsca w tym przypadku: ostatnim argumentem
mv
jest miejsce docelowe. W przypadku narzędzi GNU (tj. W niewbudowanym systemie Linux lub Cygwin)-t
opcjamv
jest przydatna, aby najpierw przekazać miejsce docelowe.Jeśli nazwy plików nie mają białych znaków ani żadnego z nich
\"'
, możesz po prostu podać nazwy plików jako dane wejściowexargs
(echo
polecenie jest wbudowane w bash, więc nie podlega limitowi długości wiersza poleceń):Możesz użyć
-0
opcji, abyxargs
użyć danych rozdzielanych znakami null zamiast domyślnego formatu cytowanego.Alternatywnie możesz wygenerować listę nazw plików za pomocą
find
. Aby uniknąć rekurencji w podkatalogach, użyj-type d -prune
. Ponieważ dla wymienionych plików obrazów nie określono żadnej akcji, przenoszone są tylko inne pliki.(Obejmuje to pliki kropkowe, w przeciwieństwie do metod wieloznacznych powłoki).
Jeśli nie masz narzędzi GNU, możesz użyć powłoki pośredniej, aby uzyskać argumenty we właściwej kolejności. Ta metoda działa na wszystkich systemach POSIX.
W Zsh możesz załadować
mv
wbudowane :lub jeśli wolisz pozwolić,
mv
a inne nazwy nadal odnoszą się do poleceń zewnętrznych:lub z globami w stylu ksh:
Alternatywnie, używając GNU
mv
izargs
:źródło
shopt -s extglob
to włączyć. Brakowało mi kroku wfind
poleceniach, naprawiłem je.find
Polecenia, które opublikowałem (teraz) działają. Musisz wkleić część podczas wklejania kopii.!
? Jest to bardziej wyraźne i łatwiejsze do zrozumienia niż nieparzyste końcowe-o
. Na przykład! -name '*.jpg' -a ! -name '*.png' -a ! -name '*.bmp'
Jeśli praca z jądrem Linuksa wystarczy, możesz to zrobić
to zadziała, ponieważ jądro Linuksa zawierało łatkę około 10 lat temu, która zmieniła limit argumentów w zależności od wielkości stosu: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/ commit /? id = b6a2fea39318e43fee84fa7b0b90d68bed92d2ba
Aktualizacja: jeśli czujesz się odważny, możesz powiedzieć
i będziesz w porządku z dowolnymi rozszerzeniami powłoki, o ile masz wystarczającą ilość pamięci RAM.
źródło
ulimit -s unlimited
i będzie działać dla praktycznie nieograniczonej liczby plików.ulimit -s unlimited
rzeczywistej granicy linii polecenia jest 2 ^ 31 lub 2 Gb. (MAX_ARG_STRLEN
w źródle jądra.)Limit przekazywania argumentów systemu operacyjnego nie ma zastosowania do rozszerzeń, które mają miejsce w interpretatorze powłoki. Oprócz użycia
xargs
lubfind
, możemy po prostu użyć pętli powłoki, aby rozbić przetwarzanie na poszczególnemv
polecenia:Używa tylko funkcji i narzędzi POSIX Shell Command Language. Ten jednowarstwowy jest wyraźniejszy dzięki wcięciu, z usuniętymi niepotrzebnymi średnikami:
źródło
mv
procesów, zamiast tylko kilku potrzebnych przy użyciufind
rozwiązania POSIX opublikowanego przez @Gilles. Innymi słowy, w ten sposób powstaje wiele niepotrzebnych rezygnacji z procesora.case
oświadczenie o wyniku*
rozszerzenia w celu odfiltrowania kilku rozszerzeń jest równoważne oryginalnemu!(*.jpg|*.png|*.bmp)
wyrażeniu.find
Odpowiedź jest w rzeczywistości nie równoważnym; schodzi do podkatalogów (nie widzę-maxdepth
predykatu).-name . -o -type d -prune -o
chroni przed zejściem do podkatalogów.-maxdepth
najwyraźniej nie jest zgodny z POSIX, chociaż nie jest to wspomniane na mojejfind
stronie man.Aby uzyskać bardziej agresywne rozwiązanie niż wcześniej oferowane, pobierz źródło jądra i edytuj
include/linux/binfmts.h
Zwiększ rozmiar
MAX_ARG_PAGES
do czegoś większego niż 32. Zwiększa to ilość pamięci, którą jądro pozwoli na argumenty programu, tym samym umożliwiając określenie twojego poleceniamv
lubrm
polecenia dla miliona plików lub cokolwiek robisz. Ponownie skompiluj, zainstaluj, uruchom ponownie.STRZEC SIĘ! Jeśli ustawisz zbyt dużą wartość dla pamięci systemowej, a następnie uruchom polecenie z dużą liczbą argumentów, BĘDĄ RZECZY! Zachowaj szczególną ostrożność, robiąc to w systemach z wieloma użytkownikami, dzięki czemu złośliwi użytkownicy mogą zużywać całą pamięć!
Jeśli nie wiesz, jak ręcznie skompilować i ponownie zainstalować jądro, prawdopodobnie najlepiej udajesz, że ta odpowiedź na razie nie istnieje.
źródło
Prostsze rozwiązanie wykorzystujące
"$origin"/!(*.jpg|*.png|*.bmp)
zamiast bloku catch:Dzięki @Score_Under
W przypadku skryptu wielowierszowego możesz wykonać następujące czynności (zwróć uwagę
;
przeddone
upuszczeniem):Aby zrobić bardziej ogólne rozwiązanie, które przenosi wszystkie pliki, możesz wykonać jedną linię:
Który wygląda tak, jeśli wykonasz wcięcie:
To bierze każdy plik w źródle i przenosi je jeden po drugim do miejsca docelowego. Cudzysłowy
$file
są konieczne w przypadku, gdy w nazwach plików znajdują się spacje lub inne znaki specjalne.Oto przykład tej metody, która działała idealnie
źródło
!(*.jpg|*.png|*.bmp)
. Możesz dodać to do swojej pętli for poprzez globbing,"$origin"/!(*.jpg|*.png|*.bmp)
który pozwoliłby uniknąć konieczności użycia przełącznika użytego w odpowiedzi Kaz i zachować proste ciało pętli for.Czasami najłatwiej jest po prostu napisać mały skrypt, np. W Pythonie:
źródło
Możesz obejść to ograniczenie, wciąż je wykorzystując,
mv
jeśli nie masz nic przeciwko uruchomieniu go kilka razy.Możesz przenosić porcje na raz. Załóżmy na przykład, że masz długą listę alfanumerycznych nazw plików.
To działa. Następnie wybij kolejny duży kawałek. Po kilku ruchach możesz po prostu wrócić do korzystania
mv ./subdir/* ./
źródło
Oto moje dwa centy, dodaj to do
.bash_profile
Stosowanie
źródło