Respostas:
mv
não puder mesclar ou substituir diretórios, ele falhará com a mensagem "mv: não é possível mover 'a' para 'b': diretório não vazio" , mesmo quando você estiver usando a --force
opção
Você pode contornar isso usando outras ferramentas (como rsync
, find
ou até mesmo cp
), mas você precisa considerar com cuidado as implicações:
rsync
pode mesclar o conteúdo de um diretório em outro (idealmente com a opção --remove-source-files
1 para excluir com segurança apenas os arquivos de origem que foram transferidos com êxito e com a opção usual de permissão / propriedade / preservação de tempo, -a
se desejar) rsync
a --link-dest=DIR
opção (para criar links físicos em vez de copiar o conteúdo do arquivo, sempre que possível) e --remove-source-files
obter uma semântica muito semelhante a uma regular mv
. --link-dest
necessário fornecer um caminho absoluto para o diretório de origem (ou um caminho relativo do destino à origem ). --link-dest
maneira não intencional (que pode ou não causar complicações), requer conhecer (ou determinar) o caminho absoluto para a fonte (como argumento --link-dest
) e novamente deixa uma estrutura de diretório vazia para ser limpa como por 1 .find
para recriar seqüencialmente a estrutura do diretório de origem no destino e, em seguida, mover individualmente os arquivos reais cp
pode criar links físicos (basta colocar, ponteiros adicionais para o mesmo arquivo existente), o que cria um resultado muito semelhante a uma fusão mv
(e é muito eficiente em IO, pois apenas ponteiros são criados e nenhum dado real precisa ser copiado) Qual dessas soluções alternativas (se houver) é apropriada dependerá muito do seu caso de uso específico.
Como sempre, pense antes de executar qualquer um desses comandos e faça backups.
1: Observe que rsync --remove-source-files
não excluirá nenhum diretório, então você terá que fazer algo como find -depth -type d -empty -delete
depois para se livrar da árvore de diretórios de origem vazia.
mv
implementação usada pelo Debian - a ênfase estar em julgado , uma vez que a página de manual não menciona este comportamento ...
--delete
apenas exclui arquivos no diretório de destino que não existem no diretório de origem.
-H
função ou pode vincular os arquivos no destino usando --link-dest
. Veja a página de manual antes de usá-los.
rsync -av /source/ /destination/
(after checking)
rm -rf /source/
--remove-source-files
tem a vantagem de remover apenas os arquivos transferidos com êxito; portanto, você pode usar find
para remover diretórios vazios e ficará com tudo o que não foi transferido sem ter que verificar rsync
a saída.
Você pode usar a -l
opção do comando cp , que cria links físicos de arquivos no mesmo sistema de arquivos em vez de cópias de dados completos. O comando a seguir copia a pasta source/folder
para uma pasta pai ( destination
) que já contém um diretório com o nome folder
.
cp -rl source/folder destination
rm -r source/folder
Você também pode usar o -P
( --no-dereference
- não desassociar links simbólicos) ou -a
( --archive
- preservar todos os metadados, também inclui a -P
opção), dependendo de suas necessidades.
cp
ao invés de rsync
já que todo sistema tem cp
e todos têm familiaridade com ele.
cp
com o tempo de operação de mv
.
-n
mv /fs1/file /fs2/
(entre sistemas de arquivos) executará uma cópia e, em seguida, uma exclusão.
mv
funcionará (desde que o diretório de destino ainda não exista), mesmo que não seja "eficiente" ou como você o chamar, cp -rl
falhará.
Eu recomendo estas quatro etapas:
cd ${SOURCE};
find . -type d -exec mkdir -p ${DEST}/\{} \;
find . -type f -exec mv \{} ${DEST}/\{} \;
find . -type d -empty -delete
ou melhor ainda, aqui está um script que implementa semântica semelhante a 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
(somente atualizar se for mais recente), mv
(em algumas versões pelo menos) também pode usar a -u
opção. No entanto, nesse caso, convém excluir os diretórios de origem não vazios e os vazios, para cobrir os casos em que os arquivos na árvore de origem não são mais novos. @chuess: Parece que pode haver vários argumentos SOURCE, se você precisar.
Aqui está uma maneira de mesclar os diretórios. É muito mais rápido que o rsync, pois apenas renomeia os arquivos em vez de copiá-los e excluí-los.
cd source; find -type f -print0 | xargs -0 -n 1 -I {} mv '{}' 'dest/{}'
dest
já for um diretório com o mesmo nome que em source
. E os arquivos serão movidos para um dest
, que está em source
. O comando não faz nada mais do quemv source/* source/dest/.
Uma maneira de conseguir isso seria usar:
mv folder/* directory/folder/
rmdir folder
Contanto que não haja dois arquivos com o mesmo nome folder
e directory/folder
, você obterá o mesmo resultado, ou seja, mesclando.
rm folder
funciona?
rm folder -fR
sempre funciona para mim
Para as cópias mais puras, eu uso o método de cópia em bloco (tar) tar (-) B.
Por exemplo, no caminho de origem ('cd', se necessário):
tar cBf - <sourcefolder> | (cd /your/target/folder ; tar xBf -)
isso cria uma cópia exata da árvore de origem, COM o proprietário e as permissões intactas. E se a pasta de destino existir, os dados serão mesclados. Somente arquivos que já existem serão substituídos.
Exemplo:
$ cd /data1/home
$ tar cBf - jdoe | (cd /data2/home ; tar xBf -)
Quando a ação de cópia é bem-sucedida, você pode remover a fonte ( rm -rf <source>
). Obviamente, essa não é uma ação exata: os dados serão copiados até você remover a fonte.
Como opção, você pode ser detalhado (exibir na tela o arquivo que está sendo copiado), com -v: tar cBvf -
c
: crioB
: leia bloco completo (para leitura de tubo)v
: verbosef
: arquivo a ser gravadox
: extrair-
: stdout / stdinsourcefolder
também pode ser *
(para qualquer coisa na pasta atual)
f -
do tar geralmente não é necessária - o padrão é ler de stdin / write para stdout.
Aqui está um script que funcionou para mim. Eu prefiro mv sobre rsync, então uso as soluções de Jewel e 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
Não é uma boa ideia usar comandos como cp ou rsync. Para arquivos grandes, levará muito tempo. O mv é muito mais rápido, pois somente atualiza os inodes sem copiar os arquivos fisicamente. Uma opção melhor é usar o gerenciador de arquivos do seu sistema operacional. Para o Opensuse, existe um gerenciador de arquivos chamado Konquerer. Ele pode mover arquivos sem realmente copiá-los. Possui a função "recortar e colar", como no Windows. Basta selecionar todos os subdiretórios no diretório A. Clique com o botão direito e "vá para" o diretório B, que pode conter subdiretórios com os mesmos nomes. Ele irá fundi-los. Também existem opções para substituir ou renomear arquivos com o mesmo nome.
mv
é usado.
Solução Python
Como não consegui encontrar uma solução pré-existente satisfatória, decidi criar um script Python rápido para alcançá-la.
Em particular, esse método é eficiente porque apenas percorre a árvore do arquivo de origem uma vez que estiver de baixo para cima.
Ele também permitirá que você ajuste rapidamente coisas como manipulação de substituição de arquivos ao seu gosto.
Uso:
move-merge-dirs src/ dest/
moverá todo o conteúdo de src/*
para dest/
e src/
desaparecerá.
mover-mesclar-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)
Consulte também: https://stackoverflow.com/questions/22588225/how-do-you-merge-two-directories-or-move-with-replace-from-the-windows-command
Este é o comando para mover arquivos e pastas para outro destino:
$ mv /source/path/folder /target/destination/
Lembre - se : o mv
comando não funcionará se a pasta estiver aberta (ou seja, já existe outra pasta com o mesmo nome no destino) e o diretório não está ativado .
mv: não é possível mover '/ source / path / folder' para '/ target / destination / folder': diretório não vazio
Se a pasta de destino estiver vazia, o comando acima funcionará bem.
Portanto, para mesclar as duas pastas em qualquer caso,
faça-o em 2 comandos:
$ cp -rf /source/path/folder /target/destination/
$ rm -rf /source/path/folder
Ou combine ambos como um comando único:
$ cp -rf /source/path/folder /target/destination/ && rm -rf /source/path/folder
mv = mover
cp = copiar
rm = remover-r para diretório (pasta)
-f força a execução
mv
. Essa resposta seria melhor com uma verdade mais ampla. Linux, BSD e Unix "real", ou uma referência do POSIX ou SUS.