BASH - mescla diretórios ao usar mv

5

Acabei de usar o BASH, para poder mover todo o conteúdo de um diretório para outro. Mas a questão é, eu estava esperando para mesclar os diretórios. Estou usando o cron job para executar este script.

#!/bin/bash

shopt -s dotglob nullglob
mv mv_schedule/* public_html/

Fonte: /mv_schedule/ (contendo pastas / arquivos)

/files/
4.html
5.html
/assets/
sitemap.xml

Destino: /public_html/ (as pastas anteriores já existem)

/files/
1.html
2.html
3.html
/assets/
sitemap.xml

Então, o que eu quero é que todos os novos arquivos desses diretórios dentro de /mv_schedule/ se fundam com os de /public_html/ , e que os arquivos que já existem nele sejam substituídos pelos que vêm de /mv_schedule/ .

No momento, ele está retornando esse erro por e-mail quando eu tento isso com o script atual:

mv: cannot move 'mv_schedule/assets' to 'public_html/assets': Directory not empty

Como posso corrigir isso?

    
por The Bash 09.10.2013 / 07:10

3 respostas

6

O que a mensagem de erro está dizendo é que não é possível ativar o diretório de recursos porque existem arquivos dentro dele. mv um diretório significa fazer uma cópia, depois apagá-la e não pode apagá-la porque ainda contém alguns arquivos. Isso significa que você deve converter os arquivos dentro do ativo, e até mesmo os subdiretórios e arquivos dentro dos subdiretórios dentro do ativo, se existirem. Mas o comando mv que emitiu só pode copiar (e apagar) o que está presente dentro do diretório mv_schedule, não o que está presente nos subdiretórios (como ativo) dentro de mv_schedule.

O que você quer é um comando que desça a árvore de diretórios até a última folha e copie-a, algo como uma opção -r ou -R em rm, chmod, chown. No entanto, mv não tem tal opção, então você terá que usar o comando find, que desce toda a árvore de diretórios de uma raiz que você especificar, e então executa uma ação que você especificar. No seu caso, um comando adequado é:

SOURCE_DIR=$1
TARGET_DIR=$2
find $SOURCE_DIR -name '*' -type f -exec mv -f {} $TARGET_DIR \;

Isso empilha todos os arquivos em um único diretório de destino. Assume-se que você tenha passado o diretório de origem e destino como parâmetros de linha de entrada para um script bash. A opção -f evita pedir confirmação em caso de substituição, você pode mudar isso para -n (não sobrescrever) ou -i (perguntar antes de sobrescrever).

Se preferir preservar a estrutura de diretórios, lembre-se de que o comando cp tem a capacidade de descer a árvore de diretórios, para que você possa usá-la, seguido por um rm, pois esse comando também tem a capacidade de descer árvores. Um conjunto possível de comandos é:

SOURCE_DIR=$1
TARGET_DIR=$2
cp -a $SOURCE_DIR $TARGET_DIR
rm -rf $SOURCE_DIR

Observe que a opção -a no cp: preserva registros de data e hora e propriedades. Se você não se importa com essas coisas, você pode usar -R em vez disso.

    
por 09.10.2013 / 08:02
1

Excelente resposta do palswim. (Além disso, obrigado pelo upvote para os dois últimos pontos necessários para ser capaz de me upvotar!)

O cp -rl; O rm classifica o problema e com o mínimo de E / S (o cp e o rsync são estupidamente caros a esse respeito).

Existem dois pequenos problemas:

  • não é 100% atômico - são necessárias duas operações de E / S (isso também se aplica ao método rsync, já que --remove-source-files na verdade ainda requer uma operação de E / S separada).
  • não funciona se a origem e o destino estiverem em sistemas de arquivos diferentes
por 10.02.2015 / 23:47
1

Existe uma discussão mais genérica sobre este problema na seção Unix.

Você pode usar a opção -l do comando cp , que cria links físicos de arquivos no mesmo sistema de arquivos em vez de cópias de dados completas. 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

Notas:

  • Você também pode querer usar o -P ( --no-dereference - não desrefere links simbólicos) ou -a ( --archive - preservar todos os metadados, também inclui -P opção), dependendo do seu necessidades.
  • Embora haja duas etapas de "E / S" envolvidas, as etapas são operações de metadados relativamente simples que envolvem zero transferências de "dados". Assim, este método é magnitudes mais rápidas que uma solução baseada em cp (sans -l ) ou rsync.
  • Isso não funciona se suas pastas de origem e de destino estiverem em sistemas de arquivos diferentes
por 09.12.2014 / 22:37