Diferenças sintáticas no cp -r e como superá-las

5

Digamos que estamos em um diretório em branco. Então, os seguintes comandos:

mkdir dir1
cp -r dir1 dir2

Renda dois diretórios (em branco), dir1 e dir2 , onde dir2 foi criado como uma cópia de dir1 . No entanto, se fizermos isso:

mkdir dir1
mkdir dir2
cp -r dir1 dir2

Em seguida, descobrimos que dir1 foi colocado dentro de dir2 . Isso significa que o mesmo comando cp se comporta de maneira diferente, dependendo se o diretório de destino existe . Em caso afirmativo, o comando cp está fazendo o mesmo:

mkdir dir1
mkdir dir2
cp -r dir1 dir2/.

Isso parece extremamente contra-intuitivo para mim. Eu teria esperado que cp -r dir1 dir2 (quando dir2 já existe) removeria o dir2 (e qualquer conteúdo) existente e o substituiria por dir1 , pois esse é o comportamento quando cp é usado para dois arquivos . Eu entendo que as cópias recursivas são um pouco diferentes por causa de como os diretórios existem no Linux (e mais amplamente em sistemas semelhantes ao Unix), mas eu estou procurando mais alguma explicação sobre por que esse comportamento foi escolhido . Pontos de bônus se você puder me indicar uma maneira de garantir que cp se comporte como eu esperava (sem ter que, por exemplo, testar e remover o diretório de destino de antemão). Eu tentei algumas opções de cp sem qualquer sorte. E suponho que aceitarei rsync soluções para o bem dos outros que acontecem com essa questão e que não conhecem esse comando.

Caso esse comportamento não seja universal, estou no CentOS, usando o bash.

    
por TTT 04.12.2014 / 15:39

1 resposta

4

O comportamento que você está procurando é um caso especial :

cp -R [-H|-L|-P] [-fip] source_file... target

[This] form is denoted by two or more operands where the -R option is specified. The cp utility shall copy each file in the file hierarchy rooted in each source_file to a destination path named as follows:

  • If target exists and names an existing directory, the name of the corresponding destination path for each file in the file hierarchy shall be the concatenation of target, a single <slash> character if target did not end in a <slash>, and the pathname of the file relative to the directory containing source_file.
  • If target does not exist and two operands are specified, the name of the corresponding destination path for source_file shall be target; the name of the corresponding destination path for all other files in the file hierarchy shall be the concatenation of target, a <slash> character, and the pathname of the file relative to source_file.

It shall be an error if target does not exist and more than two operands are specified ...

Portanto, eu diria que não é possível fazer com que cp faça o que você quer.

Como seu comportamento esperado é " cp -r dir1 dir2 (quando dir2 já existir) removerá o dir2 (e qualquer conteúdo) existente e o substituirá por dir1 ":

rm -rf dir2 && cp -r dir1 dir2

Você nem precisa verificar se dir2 existe.

A solução rsync estaria adicionando um / à fonte para que não copiasse dir1 em dir2 , mas copiasse o conteúdo de dir1 para dir2 (ainda será manter arquivos existentes em dir2 ):

$ tree dir*
dir1
└── test.txt
dir2
└── test2.txt

0 directories, 2 file
$ rsync -a dir1/ dir2
$ tree dir*           
dir1
└── test.txt
dir2
└── test.txt
└── test2.txt

0 directories, 3 files
$ rm -r dir2          
$ rsync -a dir1/ dir2
$ tree dir*           
dir1
└── test.txt
dir2
└── test.txt

0 directories, 2 files
    
por 08.12.2014 / 20:03