Por que não consigo lidar com a existência de um diretório de mesmo nome no destino?

5

mv não pode mover um diretório para um destino com um diretório de mesmo nome:

$ mv fortran/ imperative_PLs/
mv: cannot move ‘fortran/’ to ‘imperative_PLs/fortran’: Directory not empty
  1. Por que mv não funciona nesse caso? Isso pode ser explicado a partir das chamadas do sistema mv chama? (Compare com rsync que pode)

  2. Por que mv foi projetado para não funcionar nesse caso? Qual é a razão ou ponto?

por Tim 25.03.2016 / 22:17

4 respostas

5
  1. mv não funciona neste caso porque não foi projetado para isso. As chamadas do sistema são (provavelmente)

    • Mover para o mesmo sistema de arquivos: rename (originalmente link e unlink )
    • Mover-se pelos sistemas de arquivos: cópia de arquivo recursiva seguida por recursiva unlink
  2. Opinião: Eu acho que não é tanto que ele tenha sido projetado não para funcionar, já que ele não foi projetado para lidar com esse caso de uso. Para uma ferramenta "simples" destinada a fazer bem uma coisa, é necessário fornecer um conjunto de opções para indicar a mv quais desses caminhos de ação devem ser executados:

    • Para salvar com um erro, como na implementação atual
    • Para mesclar, resgatando com um erro se já existir um arquivo
    • Para mesclar, substituir quaisquer arquivos de destino que já existam

Se a ação de mesclagem / substituição for o que você deseja, você poderá implementá-la facilmente com cp seguido por rm ou usando um dos utilitários de cópia da árvore de arquivos tar , pax , etc.

    
por 25.03.2016 / 22:35
10

mv e rsync não são programas semelhantes. Em particular, mv está frequentemente tentando simplesmente renomear objetos. Se estiver no mesmo sistema de arquivos, ele não copia o conteúdo.

Se você ainda não tivesse imperative_PLs/fortran , então mv pegaria o diretório fortran existente e renomeia para esse ponto na árvore.

Mas você já tem um diretório (com conteúdo) naquele local. Como um nome só pode referenciar um único objeto, o diretório existente teria que ser removido ou renomeado. mv assume que você não quer fazer nada e aborta.

rsync copia os arquivos individuais e outros conteúdos dentro de fortran e os coloca no diretório imperative_PLs/fortran existente.

Pense nisso como rename , e o comportamento pode parecer mais compreensível.

    
por 25.03.2016 / 22:35
6

mv é, na verdade, rename sob a capa.

Se você mover um arquivo para outro arquivo, mv pressupõe que você sabe o que está fazendo e sobrescreve o arquivo de destino.

Se você mover um diretório para outro diretório, mv assumirá que você deseja manter o nome de base do diretório original e criá-lo no diretório de destino. Se ainda não houver um diretório com esse nome no lado do destino ou se existir um diretório com esse nome, mas estiver vazio, a operação será bem-sucedida.

No entanto, se o diretório de destino já existir e não estiver vazio, isso não será mais um rename , mas deverá ser um arquivo recursivo e uma remoção de diretório. rename não foi projetado para fazer isso, então, mv não vai mais longe, pois assume que você não queria fazer isso e falha também.

    
por 25.03.2016 / 22:39
3

A mensagem de erro ao mover entre sistemas de arquivos é um pouco mais detalhada:

# mv a/foo b/bar
mv: inter-device move failed: 'a/foo' to 'b/bar/foo'; unable to remove target: Directory not empty

Portanto, não está tentando mesclar diretórios como você parece esperar, em vez disso, está removendo o destino antes de renomear a origem; e remover para diretórios só funciona quando está vazio.

Em termos de syscalls, dentro do mesmo sistema de arquivos, é apenas rename()

rename("a/foo", "a/bar/foo")            = -1 ENOTEMPTY (Directory not empty)

Ao mover-se entre os sistemas de arquivos, é primeiro rename() a detecção deste caso e deles uma tentativa simples de rmdir() .

rename("a/foo", "b/bar/foo")            = -1 EXDEV (Invalid cross-device link)
rmdir("b/bar/foo")                      = -1 ENOTEMPTY (Directory not empty)

mv poderia fazer mais esforço, mas não quer. ;)

    
por 25.03.2016 / 22:37