Por que o programa unix mv não precisa da opção -R (recursiva) para diretórios, mas o cp precisa?

58

Sempre fico bagunçado quando preciso usar cpou mv: "Preciso de -Ropção ao trabalhar com dir?" No GNU, coreutils cpprecisa -Re mvnão.

Eu simplesmente não consigo encontrar nenhuma razão pela qual cpprecisa de -Ropção para copiar dirs e mvnão. Eu acho que cping dirs sem -R(mas se comportar recursivamente como há -Re como mvfaz) não causaria problemas, exceto quebrar os hábitos de alguém ao usar a ferramenta.

Você conhece alguma explicação? Pode ser que tivesse uma razão há muito tempo?


Pergunta adicional: por que os desenvolvedores do coreutils não fazem cpdiretórios de cópia recursivamente por padrão?

rslnx
fonte

Respostas:

45

Um diretório é (conceitualmente) um "arquivo" especial que contém uma lista de nomes e os números dos inodes para os quais esses nomes apontam. Alguns dos nomes podem ser subdiretórios. Há uma entrada especial ..que aponta para o diretório pai.

Portanto, é claro, é fácil alterar o nome de um arquivo: basta alterar o nome na entrada do diretório, nada mais. Isso mantém se o arquivo é realmente um arquivo ou é um "arquivo" usado para armazenar o conteúdo de outro diretório. De fato, o mesmo renamesyscall faz as duas coisas.

Copiar, no entanto, é uma operação muito menos trivial. Você pode simplesmente copiar o diretório "arquivo", mas então você tem dois diretórios onde os arquivos são os mesmos (seriam links físicos). Se você tivesse um sistema que permita links diretos para diretórios, seria o caso, mas como nenhum sistema moderno permite isso, pelo menos para não-root, é necessário fazer essa cópia para cada subdiretório. Você pode realmente solicitar cpesse comportamento com cp -lR: -lpara link -Rfísico , para essa recursão.

Mas deixar tudo vinculado provavelmente não é o que você deseja. Em vez disso, você deseja cpcopiar cada arquivo. Essa é uma operação bastante cara: cada arquivo deve ser lido na memória e gravado novamente em disco em um segundo local. Na verdade, são necessários vários syscalls para abrir, ler, gravar e fechar os arquivos, e isso deve ser repetido para cada arquivo.

Os sistemas de arquivos tradicionais também funcionam dessa maneira no disco. Não há como copiar um monte de arquivos, além de examiná-los individualmente e copiá-los, e esses são os tipos de sistemas de arquivos que estavam em uso quando os utilitários básicos da linha de comando foram projetados.

derobert
fonte
está mvpassando de um sistema de arquivos para outro o mesmo "basta alterar o nome na entrada do diretório"?
rslnx
5
Não, o sistema de arquivos cruzados é igual a uma cópia + exclusão (na verdade, o renamesyscall falhará no sistema de arquivos cruzados). Não tenho certeza se, historicamente, mvaté suportamos movimentos cross-fs.
Derobert
9
Posso dizer, por experiência direta e não especulação, que o clássico mvnão suportava movimentos entre dispositivos. Ele costumava tentar rename()ae imprimir uma mensagem de erro se falhasse. Ainda me lembro do sentimento chocado que tive na primeira vez em que acidentalmente usei o novo recurso. Por que esse MV está demorando tanto? Oh, está fazendo uma cópia recursiva que eu não pretendia!
22612 Alan Curry
5
@RuslanKhusnullin As opções de linha de comando para comandos comuns são muito difíceis de alterar, devido ao uso em scripts de shell. Alguém pode estar dependendo do atual comportamento de recusar-para-copiar-dirs do cp. Provavelmente, o material cross-fs foi considerado menos provável de causar quebra, embora, como você possa ver, ainda tenha surpreendido Alan.
Derobert 22/08/12
11
@derobert, não funcionou (o sistema de arquivos cruzados mvfuncionou apenas para arquivos individuais no BSD 4.2 no VAX).
vonbrand
21

Deixe-me começar fazendo outra pergunta:

Qual é a diferença entre cpe cp -R?

Bem, sem o -Rsinalizador, só é possível copiar arquivos, porque é bastante incomum que alguém queira copiar um diretório de forma não recursiva: uma cópia não recursiva resultaria em um segundo nome para o diretório, apontando diretamente para o mesmo diretório estrutura. Como isso raramente é o que as pessoas desejam e, na verdade, existe um programa separado que faz isso ( ln), uma cópia não recursiva dos diretórios não é permitida.

Qual seria então a diferença entre mve mv -R?

mv a bapenas renomeia uma única entrada no diretório, portanto, se um diretório for mved, seu conteúdo também será automaticamente movido. Nesse sentido, mvjá fornece a propriedade recursiva, ou seja, a "renomeação" de todas as entradas no diretório renomeado, por exemplo, de a/1para b/1. Um mvque não faz isso, ou seja, que renomeia um diretório apara b, mas mantém a/1como a/1, não é o que as pessoas entendem quando se referem a mover algo: Quando você move um armário, o conteúdo do armário também é movido. Essa outra operação, movendo um diretório sem seu conteúdo, também já está disponível, é chamada mkdir.

daniel kullmann
fonte
2
É isso mesmo, eu estava pensando cpe mvcomo operações denominadas: 'fazer uma cópia' e 'mover'. Portanto, se eu quiser fazer uma cópia de uma xícara de café, esperaria ter outra xícara de café com o mesmo recheio (bebida de café). O problema é que as ferramentas não se destinam a 'pessoas comuns', mas a nerds que conhecem a estrutura do disco e do sistema de arquivos, não a entidades virtuais como arquivos e diretórios de arquivos.
rslnx
11
Resposta bem estruturada e fundamentada.
Spedge
11
@RuslanKhusnullin Sua analogia com o café funciona para cpe mvtambém - não requer nenhum nível de "nerdice" para entender, apenas senso comum básico. Uma cópia verdadeira de uma xícara de café não é uma xícara vazia - é necessário copiar recursivamente não apenas a xícara, mas também todo o seu conteúdo (o café). No entanto, quando você move uma xícara de café, não precisa mover o conteúdo separadamente - o conteúdo se move naturalmente com o recipiente.
Jw013
11
@ jw013 Você me impressionou com "quando você move uma xícara de café, não precisa mover o conteúdo separadamente", isso realmente faz sentido, obrigado. Mas é outra camada de abstração. Eu acho que você quer dizer "tratar um arquivo como um inode", enquanto eu penso em arquivos como sequências de bytes sem meta-informação.
rslnx
6

Normalmente, quando estou confuso com a lógica do Unix, olho para o Plan9 para ver como os inventores do Unix implementaram as mesmas tarefas anos depois, sem comprometer a compatibilidade com versões anteriores.

Portanto, o Plan9 oferece cpe mvferramentas para operar apenas com arquivos.

`cp f1 f2` creates f2 and copies f1's contents into it.
`mv f1 f2` renames f1 to f2 if f1 and f2 are in the same dir
           does `cp f1 f2 && rm f1` else
           can rename dirs (`mv d1 d2`) but will not move dir to another dir.

Para copiar um diretório, existe dircprealmente @{cd fromdir && tar c .} | @{cd todir && tar xT}(sintaxe do shell rc)

Para mover um dir eu acho que só dircp d1 d2 && rm -r d1

Acho que essa decisão de limitar cpe apenas mvpara operações de arquivo (não dirs) traz mais clareza às operações do disco e o uso tarpara copiar árvores de arquivos é muito confortável para a compreensão e o script.

rslnx
fonte