Przenoszenie milionów plików do innego katalogu ze specyficznymi wzorami nazw

10

Mam miliony plików z następującą nomenklaturą na komputerze z systemem Linux:

1559704165_a1ac6f55fef555ee.jpg

Pierwsze 10 cyfr to znacznik czasu, a następujące po nich _to konkretne identyfikatory. Chcę przenieść wszystkie pliki pasujące do określonych identyfikatorów plików do innego folderu.

Próbowałem tego w katalogu z plikami

find . -maxdepth 1 -type f | ??????????_a1ac*.jpg |xargs mv -t "/home/ubuntu/ntest"

Jednak pojawia się błąd wskazujący:

bash 1559704165_a1ac6f55fef555ee.jpg: command not found

Kiedy próbowałem, mv ??????????_a1ac*.jpg pojawia się zbyt długi błąd listy argumentów. Mam co najmniej 15 różnych wzorów nazw plików. Jak je przenieść?

Morela
źródło
1
Bash mówi wszystko: próbuje wykonać tę nazwę pliku, ponieważ jest ona pierwsza w linii w drugim etapie potoku (twoja potoka w drugim etapie to | ??????????_a1ac*.jpg: bash rozwija ją do kilku nazw plików, pierwszą rzeczą jest to 1559704165_a1ac6f55fef555ee.jpg, że skończysz , w tym drugim etapie potoku, próbując wykonać: 1559704165_a1ac6f55fef555ee.jpg next_matching_filename 3rd_matching_filename ... nth_matching_filenameMyślę, że zamiast tego próbowałeś przefiltrować do tej nazwy pliku (zobacz odpowiedzi poniżej)
Olivier Dulac

Odpowiedzi:

15

Powinieneś użyć:

find . -maxdepth 1 -type f -name '??????????_a1ac*.jpg' \
-exec mv -t destination "{}" +

Tak więc maxdepth 1środki, które chcesz wyszukać w bieżącym katalogu bez podkatalogów.

type f oznacza znajdź tylko pliki.

name '??????????_a1ac*.jpg' to wzorzec pasujący do szukanego pliku.

mv -t destination "{}" +oznacza przeniesienie dopasowanych plików do miejsca docelowego. Tutaj +dodaje nowe dopasowane pliki do poprzedniego, takie jak:

mv -t dest a b c d

Tutaj abcd to różne pliki.

Prvt_Yadav
źródło
Dziękujemy za zwięzłe udzielenie odpowiedzi na pytanie tej osoby. Zamiast po prostu zrzucić rozwiązanie, może mógłbyś wyjaśnić, jak / co / dlaczego. Zamiast być użytecznym dla jednej osoby, raz, może być przydatna dla wszystkich przez cały czas. To samo pytanie zostało zadane i udzielono odpowiedzi niezliczoną ilość razy w ciągu ostatnich 40-50 lat. Problem polega na tym, że nigdy nie zostało to dobrze wyjaśnione. Naucz człowieka łowić ryby. Tymczasem: gnu.org/software/findutils/manual/html_node/find_html/... i jak to często bywa, Wikipedia jest bardziej przydatna niż oficjalne dokumenty: en.wikipedia.org/wiki/Find_ ( Unix)
głosy
Zobacz zaktualizowaną odpowiedź.
Prvt_Yadav
Zauważ, że -tjest to rozszerzenie GNU, więc może nie być dostępne w innych typach pochodnych UNIX.
Kevin
Kiedy mówisz „Podwójne cudzysłowy zapobiega dzieleniu słów”. Zakładam, że masz na myśli "{}", w którym to przypadku chcę podkreślić, że {}nie jest on rozszerzany przez powłokę i nie trzeba go cytować. Powłoka przechodzi, {}by znaleźć i znaleźć, widzi {}i zastępuje ją ścieżkami. Find exec nie używa parsera powłoki i nie dokonuje własnego podziału słów. Cytując, nie wyrządza to żadnej szkody, po prostu podane uzasadnienie jest nieco niedokładne.
jw013,
@ jw013 dzięki.
Prvt_Yadav
11

Twoje rozkaz

find . -maxdepth 1 -type f | ??????????_a1ac*.jpg |xargs mv -t "/home/ubuntu/ntest"

Przerzuca listę wszystkich plików DO wszystkich plików!

find . -maxdepth 1 -type f -name `*_a1ac*.jpg` -print0 |\
xargs  -0 -r mv -t "/home/ubuntu/ntest"

da rade.

waltinator
źródło
1
wielkie dzięki ... twoje rozwiązanie też zadziałało ... dziękuję za poinformowanie mnie, gdzie popełniłem błąd
Apricot
8

Jesteś bardzo blisko. Powinieneś użyć -nameopcji do find. I pamiętaj, aby zacytować wzór.

Więc

find . -maxdepth 1 -type f -name '??????????_a1ac*.jpg' |xargs mv -t "/home/ubuntu/ntest"
Stephen Harris
źródło
Wielkie dzięki ... twoje rozwiązanie również zadziałało ... dodatkowe podziękowania za poinformowanie mnie, że byłem blisko rozwiązania ... jest to motywacja dla nowicjusza takiego jak ja
Apricot
1
powinieneś dodać -print0jako ostatni argument do find (zamiast domyślnego: -print) i dodać -0jako pierwszą opcję do xargs (tj xargs -0 mv -t "/home/ubuntu/ntest". :) . w ten sposób można obsłużyć wszelkiego rodzaju dziwne nazwy plików (ze spacjami, „newline” itp.). find . -maxdepth 1 -type f -name '??????????_a1ac*.jpg' -print0 |xargs -0 mv -t "/home/ubuntu/ntest" (działa tylko z znalezieniem podobnym do GNU)
Olivier Dulac
2

Nie tak „dobre” jak findrozwiązania, ale innym prawidłowym rozwiązaniem jest mvzwiększenie szczegółowości poleceń.

Robi to 4096 ruchów, przy mniejszej liczbie plików przenoszonych na mvoperację.

FILEPAT=a1ac
for i in $(seq $((0x000)) $((0xfff))); 
do 
   H=$(printf '%x\n' $i)
   mv 1559704165_${FILEPAT}${H}*.jpg /home/ubuntu/ntest
done
RonJohn
źródło
To sprytny hack dla osób bez find(z jakiegokolwiek powodu).
las
-1

Jeśli chcesz przenieść pliki na ten sam system hosta, co, jak sądzę, robisz ze swoim mv, rsyncmoże być szybszą opcją:

rsync -av --inplace -W /source/??????????_a1ac*.jpg /home/ubuntu/ntest/

--inplacei -Wsą ustawione na przyspieszenie procesu.

Jeśli to spowoduje, że kolejny argument listy będzie zbyt długi, możesz podać listęrsync

Utwórz listę za pomocą na przykład find

find . -maxdepth 1 -type f -name '??????????_a1ac*.jpg' > /tmp/my_image_list.txt

i daj to rsync

rsync -av --inplace -W --files-from=/tmp/my_image_list.txt /path/to/files /home/ubuntu/ntest/

Oto źródło /path/to/files, ponieważ rsyncpotraktuje podaną przez ciebie listę w stosunku do twojego źródła.


Chodzi o to, że: rsyncjest szybszy niż mv, jeśli pliki nie są w tym samym systemie plików .

Robert Riedl
źródło
Prawdopodobnie trafi ten sam błąd „zbyt długiej listy argumentów”, o którym wspominał OP
Grump
@ Grump, aby tego uniknąć, OP mógłby zapisać listę plików do skopiowania do pliku, tj. find . -maxdepth 1 -type f -name '??????????_a1ac*.jpg' > /tmp/my_image_list.txtA następnie przekazać ją do rsync --files-from=/tmp/my_image_list.txt. Chodzi o to, że rsyncjest szybszy. Chyba że pliki znajdują się w tym samym systemie plików, czego OP nie wskazał.
Robert Riedl
@RobertRiedl: powinieneś edytować swoją odpowiedź i dodać tę informację. Komentarze mogą być nietrwałe.
NickD
@NickD, zaktualizowałem swoją odpowiedź.
Robert Riedl,