Jak skopiować-scalić dwa katalogi?

112

Mam dwa katalogi obrazów i obrazy2 o tej strukturze w systemie Linux:

/images/ad  
/images/fe  
/images/foo  

... i inne 4000 folderów

a drugi jest jak:

/images2/ad  
/images2/fe  
/images2/foo

... i inne 4000 folderów

Każdy z tych folderów zawiera obrazy, a nazwy katalogów pod obrazami i obrazami2 są dokładnie takie same, jednak ich zawartość jest inna. Następnie chcę wiedzieć, jak mogę skopiować-scalić obrazy / images2 / ad do obrazów / reklamy, obrazy / images2 / foo do obrazów / foo i tak dalej ze wszystkimi 4000 folderami ..

ssierral
źródło
1
czy pliki końcowe mają takie same nazwy w obu katalogach?
Simply_Me
Nie ... na przykład w obrazach / reklamach są 1.jpg, 2.jpg i 3.jpg. Ale na zdjęciach 2 / reklama są 4.jpg i 5.jpg
ssierral
4
@AmirAliAkbari, nie sądzę, że jest to duplikat - drugie pytanie w zasadzie brzmi: „czy mv łączy się?” (odpowiedź: nie). To pytanie dotyczy sposobu łączenia 2 hierarchii katalogów.
maxschlepzig

Odpowiedzi:

173

To jest zadanie dla rsync . Nie ma korzyści z robienia tego ręcznie za pomocą pętli powłoki, chyba że chcesz przenieść plik zamiast go skopiować.

rsync -a /path/to/source/ /path/to/destination

W Twoim przypadku:

rsync -a /images2/ /images/

(Zwróć uwagę, że slash będzie włączony images2, w przeciwnym razie zostanie skopiowany /images/images2).

Jeśli obrazy o tej samej nazwie istnieją w obu katalogach, powyższe polecenie zastąpi /images/SOMEPATH/SOMEFILEje /images2/SOMEPATH/SOMEFILE. Jeśli chcesz zastąpić tylko starsze pliki, dodaj opcję -u. Jeśli chcesz zawsze zachować wersję /images, dodaj opcję --ignore-existing.

Jeśli chcesz przenieść pliki /images2z rsync, możesz przekazać tę opcję --remove-source-files. Następnie rsync kopiuje kolejno wszystkie pliki i po zakończeniu usuwa każdy plik. Jest to o wiele wolniejsze niż przenoszenie, jeśli katalog źródłowy i docelowy znajdują się w tym samym systemie plików.

Gilles
źródło
14
..dodaj -P, jeśli chcesz zobaczyć postępy.
Meetai.com
1
Dodam, że nie ma żadnych korzyści z korzystania ze skomplikowanych pętli powłoki tu nawet jeśli nie chcesz, aby przenieść je zamiast kopiowania ich-w tym przypadku po prostu użyć rsync, a następnie rm -r /images.
Wildcard
1
Chciałbym również zauważyć, że ważne jest dołączenie ukośników końcowych dla każdego katalogu . Na przykład, jeśli po prostu uruchomiłeś rsync -a images images2, po prostu skopiuje obrazy2 do obrazów zamiast ich scalania.
Kyle Challis
1
@ s3cur3 Oh. Od 2 do (domyślnie) 1. To nieintuicyjne. Dzięki, naprawiłem swoją odpowiedź.
Gilles
1
@MaxCoplan Nie. Rsync nie jest narzędziem interaktywnym.
Gilles
43

Najlepszym wyborem, jak już napisano, jest oczywiście rsync. Niemniej jednak również unison byłby świetnym oprogramowaniem do wykonywania tej pracy. Oba mogą być używane w kilku systemach operacyjnych.

Rsync

rsync synchronizuje w jednym kierunku od źródła do miejsca docelowego. Dlatego następujące oświadczenie

rsync -avh --progress Source Destination

synchronizuje wszystko od źródła do miejsca docelowego . Scalony folder znajduje się w lokalizacji docelowej .

-a oznacza „archiwizuj” i kopiuje wszystko rekurencyjnie od źródła do miejsca docelowego, zachowując prawie wszystko.

-v daje więcej danych wyjściowych („pełne”).

-h dla czytelnego dla człowieka.

- postęp, aby pokazać, ile pracy zostało wykonane.

Jeśli chcesz tylko zaktualizować do docelowego folderu z nowszych plików z folderu źródłowego:

rsync -avhu --progress source destination

Unisono

unison synchronizuje w obu kierunkach. Dlatego następujące oświadczenie

unison Source Destination

synchronizuje oba katalogi w obu kierunkach i ostatecznie źródło równa się celowi To tak, jakby dwukrotnie wykonać rsync ze źródła do dest i odwrotnie.

Bardziej zaawansowane zastosowania można znaleźć na stronach podręcznika użytkownika lub w następujących witrynach:

  1. https://www.cis.upenn.edu/~bcpierce/unison/
  2. https://rsync.samba.org/
debiarch
źródło
2
Chcę wspomnieć, że poprawna ścieżka do folderu powinna mieć końcowy ukośnik na końcu rsync -avh --progress source/ destination/, w przeciwnym razie folder źródłowy zostanie utworzony w folderze docelowym, przynajmniej w moim przypadku tak było.
electroid
Działa to dla mnie świetnie (z końcowym ukośnikiem w folderach). Dziękuję Ci!
Leopoldo Sanczyk
5
for dir in images2/*; do mv "$dir"/* "images/$(basename "$dir")"; done

Zapętlaj całą zawartość images2korzystania z rozszerzonego globu (aby uniknąć problemów z parsowaniem ls), a następnie mvzawartość tych elementów do pasującego wpisu w images. Używa basenamedo usuwania wiodącej images2ścieżki z globbed ścieżki.

Etan Reisner
źródło
dodaj więcej szczegółów na temat tego, co robi twoje polecenie, aby był użyteczny również dla przyszłych czytelników :)
Ramesh
1

@ inulinux12, możesz użyć następującej forpętli jednej linii z wiersza poleceń:

$ for dir in images2/*; do mv "$dir"/* "${dir/2/}"; done

Spowoduje to przeniesienie wszystkich plików z images2do imagesodpowiednich katalogów. Uwaga: zakłada się, że żadne pliki nie mają takiej samej nazwy.

Na przykład:

Przed wykonaniem:

$ ls -R images*
images:
ad  adfoo  fe
images/ad:
jpg.1  jpg.2
images/adfoo:
jpg.7
images/fe:
jpg.5
images2:
ad  adfoo  fe
images2/ad:
jpg.3
images2/adfoo:
jpg.6
images2/fe:
jpg.4

Po wykonaniu:

$ ls -R images*
images:
ad  adfoo  fe
images/ad:
jpg.1  jpg.2  jpg.3
images/adfoo:
jpg.6  jpg.7
images/fe:
jpg.4  jpg.5
Po prostu ja
źródło
3
Nie analizuj wyniku ls. mywiki.wooledge.org/ParsingLs
Etan Reisner
@EtanReisner Dziękuję za sugestię; wydaje się dość wąskie scenariusze, biorąc pod uwagę informacje podane w pytaniu.
Simply_Me
2
@Simply_Me Chociaż to prawda, że ​​zwykle będzie dobrze, naprawdę nie chcesz, aby wybuchła, gdy trafisz na przypadek, na który nie liczyłeś. Może powodować naprawdę złe problemy. Nie wspominając już o tym, że jest to dość często (jak w tym przypadku) prawie trywialnie zastępowalne prostym globem. Zobacz moją odpowiedź jako przykład tego.
Etan Reisner,
@Simply_Me Scenariusze zawierają nazwy plików ze spacjami, co jest dość powszechne w przypadku obrazów.
Gilles
@Gilles i @Etan Reisner, dziękuję za wkład, doceniam to! Zaktualizowałem i przetestowałem moją odpowiedź, aby użyć podstawiania ciągów, i stało się to szybsze niż użycie basenamew tej konkretnej sytuacji (nie trzeba do tego dzwonić basename). Jeszcze raz dziękuję za konstruktywne komentarze.
Simply_Me,