Mesclar diretórios ao usar mv

5

Comecei a usar o BASH, para poder mover todo o conteúdo de um diretório para outro. Mas o problema é que eu esperava que ele mesclasse 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 /mv_schedule/sejam mesclados com os existentes /public_html/e que os arquivos que já existem nele sejam substituídos pelos que vierem /mv_schedule/.

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

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

Como posso consertar isso?

A critica
fonte
Você está executando este script bash como usuário root ou usuário normal? se é um usuário root, qual é a saída de alias -a/
max
Infelizmente, não tenho certeza. Estou apenas no cPanel de hospedagem compartilhada, então provavelmente não tenho acesso root verdadeiro.
The Bash

Respostas:

6

O que a mensagem de erro está dizendo é que ela não pode mv o diretório de ativos porque há 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ê também deve mover os arquivos dentro do ativo e até os subdiretórios e arquivos nos subdiretórios do ativo, se eles existirem. Mas o comando mv emitido pode apenas copiar (e apagar) o que está presente no diretório mv_schedule, não o que está presente nos subdiretórios (como ativo) dentro do mv_schedule.

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

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

Isso empilhará todos os arquivos em um único diretório de destino. Ele pressupõe que você passou o diretório de origem e destino como parâmetros da linha de entrada para um script bash. A opção -f impede a solicitação de confirmação em caso de substituição, você pode alterá-la para -n (não substitui) ou -i (perguntar antes de substituir).

Se, em vez disso, você deseja 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á-lo, seguido por uma 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 a opção -a no cp: preserva registros de data e hora e propriedades. Se você não se importa com essas coisas, pode usar -R.

MariusMatutiae
fonte
Receio não entender completamente sua resposta. Mas eu colocaria SOURCE_DIRe TARGET_DIRcom dirName/? Além disso, vejo que você mencionou -i (pergunte antes de sobrescrever). Quero que ele substitua os arquivos existentes e mescle com os diretórios existentes, para manter todos os arquivos existentes no diretório de destino e adicionar (também substituir arquivos existentes) os novos do mesmo diretório de nome da origem.
The Bash
você pode configurar SOURCE_DIR e TARGET_DIR para os valores desejados, neste caso SOURCE_DIR = mv_schedule e, em seguida, TARGET_DIR = public_html. Você pode sobrescrever com a opção -f, mas não esclareceu o que deseja fazer com os arquivos, digamos, no ativo de diretório. Eles devem 1) dentro do diretório public_html ou devem entrar no diretório public_html / assets? As duas opções que propus fazem essas duas coisas diferentes, respectivamente.
MariusMatutiae 9/10
Adicionei algumas linhas à minha resposta, tentando esclarecer.
MariusMatutiae 9/10
rm -rf $SOURCE_DIRirá remover o diretório de origem, talvez seja melhor para preservá-lo e utilização rm -rf "$SOURCE_DIR/*"- Também é aconselhável usar aspas em torno de variáveis (em nomes de diretório caso ter espaços)
Savvas Radevic
Bem, como sei que não é possível usar o mv para simplesmente mover os arquivos. Gostaria de deixar intacto o conteúdo do diretório de origem. E para esclarecer novamente para que todos entendam, é 'apenas' o conteúdo do /mv_schedule/, not the directory / mv_schedule / `em si.
The Bash
2

Há uma discussão mais genérica sobre esse problema na seção Unix.

Você pode usar a -lopçã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/folderpara 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 usar o -P( --no-dereference- não desassociar links simbólicos) ou -a( --archive- preservar todos os metadados, também inclui a -Popção), dependendo de suas necessidades.
  • Embora existam duas etapas de "E / S" envolvidas, as etapas são operações de metadados relativamente simples que envolvem zero transferências de "dados". Portanto, esse método é magnitudes mais rápido que uma -lsolução baseada em cp (sans ) ou rsync.
  • Isso não funciona se as pastas de origem e destino estiverem em sistemas de arquivos diferentes
palswim
fonte
1

Excelente resposta de palswim. (Além disso, obrigado pelo voto positivo pelos dois últimos pontos necessários para que eu pudesse votar novamente!)

O cp -rl; A rm resolve o problema e com o mínimo de E / S (cp e rsync são estupidamente caros nesse sentido).

Existem dois problemas menores:

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