Przenieś wszystkie pliki z określonym rozszerzeniem z wielu podkatalogów do jednego katalogu

43

Mam kilka plików .zip w kilku katalogach:

Fol1/Fol2
Fol3
Fol4/Fol5

Jak mam przenieść je wszystkie do wspólnego folderu podstawowego?

InquilineKea
źródło
Czy chcesz zachować strukturę katalogów? Chcesz przenieść katalogi, czy tylko pliki zip?
Jordan
Chcę tylko przenieść pliki zip. Nie dbam o katalogi - można je zostawić w spokoju lub usunąć.
InquilineKea,

Odpowiedzi:

55

Przejdź do katalogu najwyższego poziomu drzewa zawierającego pliki zip ( cd …), a następnie uruchom

mv **/*.zip /path/to/single/target/directory

Działa to natychmiast po wyjęciu z pudełka. Jeśli twoja powłoka jest bash, musisz shopt -s globstarnajpierw uruchomić (możesz i powinieneś umieścić to polecenie w swoim ~/.bashrc). Jeśli twoją powłoką jest ksh, musisz uruchomić set -o globstarnajpierw (włóż ją do swojego ~/.kshrc).

Alternatywnie, użyj find, który działa wszędzie bez specjalnego przygotowania, ale jest bardziej skomplikowany:

find . -name '*.zip' -exec mv {} /path/to/single/target/directory \;

Jeśli chcesz później usunąć puste katalogi, w zsh:

rmdir **/*(/^Fod)

W bash lub ksh:

rmdir **/*/

i powtarzaj tak długo, jak są puste katalogi do usunięcia. Alternatywnie, w dowolnej powłoce

find . -depth -type d -empty -exec rmdir {} \;
Gilles „SO- przestań być zły”
źródło
Pierwsze findpolecenie powyżej działało w bashu, ale musiało się zmienić na find . -nameetc, aby działało.
JeffThompson
1
@Jeff .jest domyślny dla GNU find, ale nie dla innych, dodałem go jawnie.
Gilles „SO- przestań być zły”
13

Jeśli chcesz tylko przenieść .zippliki, możesz zrobić coś takiego

mkdir ./zipfiles
find . -name "*.zip" -exec mv "{}" ./zipfiles \;
Bernhard
źródło
3

Jeśli używasz bash w wersji 4 lub wyższej lub zsh , możesz także użyć globowania rekurencyjnego:

mv **/*.zip /path/to/move/zip/files/to

To przeniesie TYLKO pliki, a nie ich ścieżki względne, więc mogą wystąpić kolizje.

SuperMagic
źródło
co rozumiesz przez ścieżki względne?
Kunok
2

Ten jest bezpieczny przy przenoszeniu danych i bezbłędnie, co obsługuje większość dystrybucji niezależnie od wersji. To polecenie skanuje podkatalogi, a następnie przenosi lub kopiuje do nowego katalogu docelowego.

find . -name *.flac -exec mv '{}' "./flac/" ";"
  • Uruchom to polecenie w głównym katalogu, który zawiera podkatalogi z plikami, które chcesz przenieść.
  • Gdzie możesz zmienić *.flacna coś takiego jak *.zipw twoim przypadku. Lub *.doctylko każde rozszerzenie działa.
  • i mvjest poleceniem do przenoszenia plików, lub możesz użyć cpdo skopiowania danych zamiast przenoszenia.
  • ./flac/to katalog docelowy, do którego chcę przenieść wszystkie pliki FLAC. Możesz także nadać mu pełną ścieżkę/home/myid/flac/

Pełny przykład. (w tym przypadku istnieje wiele podkatalogów z nazwą wykonawcy muzyki na, /home/myid/Music/a pliki FLAC znajdują się na różnych poziomach podkatalogów. Ponieważ nie potrzebuję folderów wykonawców, ale chcę mieć wszystkie pliki FLAC w jednym katalogu na/home/myid/Music/flac/

cd /home/myid/Music
mkdir flac
find . -name *.flac -exec mv '{}' "./flac/" ";"
cd flac
ls

Następnie wyświetli wszystkie pliki FLAC.

Seandex
źródło
Co ma ;zrobić?
Francesco Boi
@FrancescoBoi należy poczekać, aż polecenie bash w tym samym wierszu zakończy pracę. a następnie przejdź do następnego wiersza poleceń bash. Jest to przydatne w przypadku poleceń zawierających skrypty, takie jak .pl lub python, ponieważ bash po prostu uruchomi go, a następnie przejdzie do następnego wiersza, więc dla bezpieczeństwa używam; po poleceniach, które wymagają czasu lub skryptu, na wypadek, gdyby bash je pomija.
Seandex,
0

Jako hack bash możesz wykorzystać moc tar:

(cd origin/;find . -exec file --mime-type "{}" \;|grep "application/zip"|cut -d ':' -f 1|xargs tar cf -)|(cd target/; tar xf -) && rm -fr origin/

Ma to tę zaletę, że nie zależy od rozszerzeń plików, ponieważ używa filepolecenia do wyboru plików do przeniesienia i zachowuje strukturę katalogów, ale nie działa ze ścieżkami zawierającymi spacje.

Ostatnim rmjest tylko usunięcie oryginalnych plików (ponieważ @InquilineKea mówi, że nie dba o oryginalny folder w komentarzu).

Oczywiście jest to szczególnie odpowiednie, jeśli folder źródłowy / docelowy / znajdują się na różnych dyskach. W przeciwnym razie inne proponowane rozwiązania są bardziej wydajne (nawet jeśli opierają się na konwencjach nazewnictwa, a nie na filetreści).

Giacomo Tesio
źródło
0

Zakładając, że masz wersje GNU find i mv, poniższe będą bardziej wydajne niż istniejące odpowiedzi oparte na znalezieniu:

find . -name '*.zip' -exec mv --target-directory='/path/to/outputdir' '{}' +

Użycie a +na końcu find -exec oznacza, że ​​lista plików zostanie przekazana do komendy mv, zamiast wykonywania jednej komendy mv na znaleziony plik. Ograniczeniem tego jest jednak to, że można umieścić „{}” tylko na końcu polecenia, co wymaga użycia opcji mv --target-directory i, o ile wiem, jest to GNU-ism.

zła
źródło