Primeiro, por que isso é feito dessa maneira? Um dos motivos é histórico: foi assim que foi feito na primeira edição do Unix .
Files are taken in pairs; the first is opened for reading,the second created mode 17. Then the first is copied into the second.
"Criado" refere-se à creat
chamada do sistema (aquela que é famosa falta de um e ), que trunca o arquivo existente pelo nome dado, se houver um.
E aqui é o código-fonte de cp
no Unix Second Edition (não consigo encontrar o código-fonte da First Edition). Você pode ver as chamadas para open
para o arquivo de origem e creat
para o segundo arquivo; e, como uma melhoria para a Primeira Edição, se o segundo arquivo for um diretório existente, cp
criará um arquivo nesse diretório.
Mas, você pode perguntar, por que isso foi feito naquela época? A resposta para "por que o Unix fez isso originalmente" é quase sempre a simplicidade. cp
abre sua fonte para leitura e cria seu destino - e a chamada do sistema para criar um arquivo sobrescreve um arquivo existente abrindo-o para gravação, porque isso permite ao chamador impor o conteúdo de um arquivo pelo nome dado se o arquivo já existia ou não.
Agora, sobre onde está documentado: no Página de manual do FreeBSD .
For each destination file that already exists, its contents are overwritten if permissions allow. Its mode, user ID, and group ID are unchanged unless the -p option was specified.
Esse texto estava presente pelo menos desde então 1990 (quando o BSD era 4.3BSD). Há uma redação semelhante no Solaris 10 :
If target_file exists, cp overwrites its contents, but the mode (and ACL if applicable), owner, and group associated with it are not changed.
O seu caso está descrito na HP -UX 10 manual:
If new_file is a link to an existing file with other links, overwrites the existing file and retains all links.
POSIX coloca em standardese. Citando Single UNIX v2 :
If dest_file exists, the following steps are taken: (…) A file descriptor for dest_file will be obtained by performing actions equivalent to the XSH specification open() function called using dest_file as the path argument, and the bitwise inclusive OR of O_WRONLY and O_TRUNC as the oflag argument.
As páginas man e as especificações que eu citei ainda especificam que se a opção -f
for passada e a tentativa de abrir / criar o arquivo de destino falhar (normalmente devido a não ter permissão para gravar o arquivo), cp
tenta para remover o alvo e criar um arquivo novamente. Isso quebraria o link físico em seu cenário.
Você pode relatar um bug de documentação contra o manual do GNU coreutils , já que não documenta esse comportamento. Mesmo a descrição de --preserve=links
, que no seu cenário levaria à remoção do link paul
e a criação de um novo arquivo, não deixa claro o que acontece sem --preserve=links
. A descrição de -f
kind implica o que acontece sem ela, mas não a soletra (“Quando copiar sem essa opção e um arquivo de destino existente não pode ser aberto para gravação, a cópia falha. No entanto, com --force,… ").