Odpowiedzi:
mv
nie można scalić ani zastąpić katalogów, zakończy się niepowodzeniem z komunikatem „mv: nie można przenieść„ a ”do„ b ”: katalog nie jest pusty” , nawet jeśli korzystasz z tej --force
opcji.
Możesz obejść ten problem za pomocą innych narzędzi (takich jak rsync
, find
a nawet cp
), ale musisz dokładnie rozważyć konsekwencje:
rsync
może łączyć zawartość jednego katalogu w inny (najlepiej z opcją --remove-source-files
1 , aby bezpiecznie usunąć tylko te pliki źródłowe, które zostały pomyślnie przesłane, oraz ze zwykłą opcją zezwolenia / posiadania / zachowania czasu, -a
jeśli chcesz) rsync
„s --link-dest=DIR
opcję (aby utworzyć hardlinki zamiast kopiowania zawartości plików, o ile to możliwe) i --remove-source-files
dostać semantyczny bardzo podobny do regularnych mv
. --link-dest
celu należy podać bezwzględną ścieżkę do katalogu źródłowego (lub ścieżkę względną od miejsca docelowego do źródła ). --link-dest
w niezamierzony sposób (co może, ale nie musi powodować powikłań), wymaga znajomości (lub ustalenia) bezwzględnej ścieżki do źródła (jako argumentu --link-dest
) i ponownie pozostawia pustą strukturę katalogów do wyczyszczenia jako na 1 .find
do sekwencyjnego odtworzenia struktury katalogu źródłowego w miejscu docelowym, a następnie pojedynczego przeniesienia rzeczywistych plików cp
może tworzyć twarde linki (po prostu dodatkowe wskaźniki do tego samego istniejącego pliku), co daje wynik bardzo podobny do scalania mv
(i jest bardzo wydajny we / wy, ponieważ tworzone są tylko wskaźniki i nie trzeba kopiować żadnych danych) To, które z tych obejść (jeśli w ogóle) jest odpowiednie, będzie bardzo zależeć od konkretnego przypadku użycia.
Jak zawsze, zastanów się, zanim wykonasz dowolne z tych poleceń, i wykonaj kopie zapasowe.
1: Pamiętaj, że rsync --remove-source-files
nie usunie żadnych katalogów, więc będziesz musiał zrobić coś takiego, find -depth -type d -empty -delete
aby pozbyć się pustego drzewa katalogów źródłowych.
mv
implementację używaną przez Debiana - nacisk został położony na wypróbowanie , ponieważ strona nie wspomina o tym zachowaniu ...
--delete
usuwa tylko pliki z katalogu docelowego , które nie istnieją w katalogu źródłowym.
-H
funkcji lub możesz dowiązać pliki w miejscu docelowym za pomocą --link-dest
. Jednak przed skorzystaniem z nich zajrzyj na stronę manuala.
rsync -av /source/ /destination/
(after checking)
rm -rf /source/
--remove-source-files
ma tę zaletę, że usuwa tylko pliki, które zostały pomyślnie przesłane, dzięki czemu można użyć find
do usunięcia pustych katalogów i pozostanie ze wszystkim, co nie zostało przesłane, bez konieczności sprawdzania rsync
danych wyjściowych.
Możesz użyć -l
opcji polecenia cp , która tworzy twarde łącza plików w tym samym systemie plików zamiast kopii pełnych danych. Następujące polecenie kopiuje folder source/folder
do folderu nadrzędnego ( destination
), który już zawiera katalog o nazwie folder
.
cp -rl source/folder destination
rm -r source/folder
Możesz także użyć -P
( --no-dereference
- nie usuwaj odsyłaczy symbolicznych) lub -a
( --archive
- zachowaj wszystkie metadane, w tym także -P
opcję), w zależności od potrzeb.
cp
raczej niż rsync
odkąd każdy system ma cp
i każdy zna go.
cp
z czasem operacji mv
.
-n
mv /fs1/file /fs2/
(w różnych systemach plików) wykona kopię, a następnie usunie.
mv
będzie działać (pod warunkiem, że docelowy katalog jeszcze nie istnieje), nawet jeśli nie będzie „wydajnie” lub jakkolwiek go nazwiesz, cp -rl
zawiedzie.
Poleciłbym te cztery kroki:
cd ${SOURCE};
find . -type d -exec mkdir -p ${DEST}/\{} \;
find . -type f -exec mv \{} ${DEST}/\{} \;
find . -type d -empty -delete
lub jeszcze lepiej, oto skrypt, który implementuje semantykę podobną do mv
:
#!/bin/bash
DEST="${@:${#@}}"
ABS_DEST="$(cd "$(dirname "$DEST")"; pwd)/$(basename "$DEST")"
for SRC in ${@:1:$((${#@} -1))}; do (
cd "$SRC";
find . -type d -exec mkdir -p "${ABS_DEST}"/\{} \;
find . -type f -exec mv \{} "${ABS_DEST}"/\{} \;
find . -type d -empty -delete
) done
rsync -u
(aktualizuj tylko, jeśli nowszy), mv
(przynajmniej w niektórych wersjach), możesz również skorzystać z tej -u
opcji. Jednak w takim przypadku możesz usunąć niepuste katalogi źródłowe, a także puste, aby uwzględnić przypadki, w których pliki w drzewie źródłowym nie są nowsze. @schuess: Wygląda na to, że może być wiele argumentów SOURCE, jeśli jest to potrzebne.
Oto sposób, który połączy katalogi. Jest znacznie szybszy niż rsync, ponieważ po prostu zmienia nazwy plików zamiast je kopiować, a następnie usuwać.
cd source; find -type f -print0 | xargs -0 -n 1 -I {} mv '{}' 'dest/{}'
dest
jest już katalogiem o takiej samej nazwie jak in source
. I pliki zostaną przeniesione do dest
, który jest w source
. Komenda nie robi nic więcejmv source/* source/dest/.
Jednym ze sposobów osiągnięcia tego jest użycie:
mv folder/* directory/folder/
rmdir folder
Dopóki nie ma dwóch plików o tej samej nazwie folder
i directory/folder
, osiągniesz ten sam wynik, tj. Scalenie.
rm folder
działa?
rm folder -fR
zawsze działa dla mnie
Do najczystszych kopii używam metody kopiowania bloków tar (-) B.
przykład z wewnątrz ścieżki źródłowej (w razie potrzeby „cd”):
tar cBf - <sourcefolder> | (cd /your/target/folder ; tar xBf -)
tworzy to dokładną kopię drzewa źródłowego, Z nienaruszonym właścicielem i uprawnieniami. A jeśli folder docelowy istnieje, dane zostaną scalone. Tylko pliki, które już istnieją, zostaną zastąpione.
Przykład:
$ cd /data1/home
$ tar cBf - jdoe | (cd /data2/home ; tar xBf -)
Gdy operacja kopiowania zakończy się powodzeniem, możesz usunąć source ( rm -rf <source>
). Oczywiście nie jest to dokładny ruch: dane będą kopiowane, dopóki nie usuniesz źródła.
Opcjonalnie możesz być gadatliwy (wyświetl na ekranie kopiowany plik), przy pomocy -v: tar cBvf -
c
: StwórzB
: czytaj pełny blok (do odczytu potoku)v
: pełnyf
: plik do zapisux
: wyciąg-
: stdout / stdinsourcefolder
może być również *
(dla czegokolwiek w bieżącym folderze)
f -
tar jest zwykle niepotrzebne - domyślnie jest to odczyt ze stdin / write na stdout.
Oto skrypt, który zadziałał dla mnie. Wolę mv niż rsync, więc używam rozwiązań Jewel i Jonathan Mayer.
#!/bin/bash
# usage source1 .. sourceN dest
length=$(($#-1))
sources=${@:1:$length}
DEST=$(readlink -f ${!#})
for SRC in $sources; do
pushd $SRC;
find . -type d -exec mkdir -p ${DEST}/{} \;
find . -type f -exec mv {} ${DEST}/{} \;
find . -type d -empty -delete
popd
done
Używanie poleceń takich jak cp lub rsync nie jest dobrym pomysłem. W przypadku dużych plików zajmie to dużo czasu. mv jest znacznie szybszy, ponieważ aktualizuje tylko i-węzły bez fizycznego kopiowania plików. Lepszą opcją jest użycie menedżera plików w systemie operacyjnym. W opensuse istnieje menedżer plików o nazwie Konquerer. Może przenosić pliki bez ich kopiowania. Ma funkcję „wycinaj i wklej” jak w systemie Windows. Wystarczy wybrać wszystkie podkatalogi w katalogu A. Kliknij prawym przyciskiem myszy i przejdź do katalogu B, który może zawierać podkatalogi o tych samych nazwach. Połączy je. Istnieją również opcje, czy chcesz zastąpić lub zmienić nazwę plików o tej samej nazwie.
mv
zostanie użyty.
Rozwiązanie Python
Ponieważ nie mogłem znaleźć zadowalającego wcześniej istniejącego rozwiązania, postanowiłem zrobić szybki skrypt Pythona, aby to osiągnąć.
W szczególności ta metoda jest wydajna, ponieważ podchodzi do drzewa plików źródłowych tylko raz oddolnie.
Umożliwi to także szybkie dostosowanie ustawień, takich jak obsługa nadpisywania plików do własnych upodobań.
Stosowanie:
move-merge-dirs src/ dest/
przeniesie całą zawartość src/*
do dest/
i src/
zniknie.
move-merge-dirs
#!/usr/bin/env python3
import argparse
import os
def move_merge_dirs(source_root, dest_root):
for path, dirs, files in os.walk(source_root, topdown=False):
dest_dir = os.path.join(
dest_root,
os.path.relpath(path, source_root)
)
if not os.path.exists(dest_dir):
os.makedirs(dest_dir)
for filename in files:
os.rename(
os.path.join(path, filename),
os.path.join(dest_dir, filename)
)
for dirname in dirs:
os.rmdir(os.path.join(path, dirname))
os.rmdir(source_root)
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description='Move merge src/* into dest. Overwrite existing files.'
)
parser.add_argument('src_dir')
parser.add_argument('dest_dir')
args = parser.parse_args()
move_merge_dirs(args.src_dir, args.dest_dir)
Zobacz także: https://stackoverflow.com/questions/22588225/how-do-you-merge-two-directories-or-move-with-replace-from-the-windows-command
To polecenie służy do przenoszenia plików i folderów do innego miejsca docelowego:
$ mv /source/path/folder /target/destination/
Pamiętaj : mv
polecenie nie będzie działać, jeśli folder jest b̲e̲i̲n̲g m̲e̲r̲ge̲d̲ (tzn. Inny folder o tej samej nazwie już istnieje w miejscu docelowym), a d̲e̲s̲t̲i̲n̲a̲t̲i̲o̲n̲ o̲n̲e̲ i̲s̲ n̲o̲t̲ e̲m̲pt̲y .
mv: nie można przenieść „/ source / path / folder” do „/ target / destination / folder”: katalog nie jest pusty
Jeśli folder docelowy jest pusty, powyższe polecenie będzie działać poprawnie.
Tak więc, aby scalić oba foldery w każdym przypadku,
Zrób to za pomocą 2 poleceń:
$ cp -rf /source/path/folder /target/destination/
$ rm -rf /source/path/folder
Lub połącz oba jako jednorazowe polecenie:
$ cp -rf /source/path/folder /target/destination/ && rm -rf /source/path/folder
mv = przenieś
cp = skopiuj
rm = usuń-r dla katalogu (folderu)
-f wymusza wykonanie
mv
. Ta odpowiedź byłaby lepsza z szerszą prawdą. Linux, BSD i „prawdziwy” Unix lub referencje z POSIX lub SUS.