Eu testei cp
com os seguintes comandos:
$ ls
first.html second.html third.html
$ cat first.html
first
$ cat second.html
second
$ cat third.html
third
Então eu copio first.html
para second.html
:
$ cp first.html second.html
$ cat second.html
first
O arquivo second.html
é substituído silenciosamente, sem erros. No entanto, se eu fizer isso em uma GUI da área de trabalho, arrastando e soltando um arquivo com o mesmo nome, o sufixo será first1.html
automaticamente. Isso evita a substituição acidental de um arquivo existente.
Por que não cp
segue esse padrão em vez de sobrescrever arquivos silenciosamente?
cp
paracp -i
ou similar, porque você vai se acostumar a ter uma rede de segurança, fazendo com que os sistemas em que ele não está disponível (a maioria deles) que muito mais arriscado. Melhor ensinar-se a rotineiramentecp -i
etc., se preferir.Respostas:
O comportamento de substituição padrão de
cp
é especificado no POSIX.Quando a especificação POSIX foi gravada, já existia um grande número de scripts, com uma suposição interna para o comportamento de substituição padrão. Muitos desses scripts foram projetados para serem executados sem a presença direta do usuário, por exemplo, como tarefas cron ou outras tarefas em segundo plano. Mudar o comportamento os teria quebrado. A revisão e modificação de todas elas para adicionar uma opção para forçar a substituição sempre que necessário foi provavelmente considerada uma tarefa enorme, com benefícios mínimos.
Além disso, a linha de comando do Unix sempre foi projetada para permitir que um usuário experiente trabalhe com eficiência, mesmo à custa de uma curva de aprendizado difícil para um iniciante. Quando o usuário digita um comando, o computador deve esperar que o usuário realmente o queira dizer, sem nenhuma adivinhação; é responsabilidade do usuário tomar cuidado com os comandos potencialmente destrutivos.
Quando o Unix original foi desenvolvido, os sistemas tinham tão pouca memória e armazenamento em massa em comparação com os computadores modernos que substituem avisos e avisos provavelmente foram vistos como luxos desnecessários e desnecessários.
Quando o padrão POSIX estava sendo escrito, o precedente foi firmemente estabelecido, e os escritores do padrão estavam bem cientes das virtudes de não quebrar a compatibilidade com versões anteriores .
Além disso, como outros já descreveram, qualquer usuário pode adicionar / ativar esses recursos por si próprio, usando aliases de shell ou mesmo criando um
cp
comando de substituição e modificando-os$PATH
para encontrar a substituição antes do comando do sistema padrão e obter a rede de segurança dessa maneira se desejado.Mas se você fizer isso, descobrirá que está criando um risco para si mesmo. Se o
cp
comando se comportar de uma maneira quando usado interativamente e de outra maneira quando chamado de um script, talvez você não se lembre de que a diferença existe. Em outro sistema, você pode acabar sendo descuidado porque está acostumado com os avisos e solicitações do seu próprio sistema.Se o comportamento nos scripts ainda corresponder ao padrão POSIX, é provável que você se acostume com os prompts no uso interativo, em seguida, escreva um script que faça algumas cópias em massa - e descubra que você novamente substituiu algo inadvertidamente.
Se você aplicar o prompt também aos scripts, o que o comando fará quando executado em um contexto que não tenha usuário por perto, por exemplo, processos em segundo plano ou tarefas cron? O script travará, abortará ou substituirá?
Interromper ou interromper significa que uma tarefa que deveria ser executada automaticamente não será executada. A não substituição às vezes também pode causar um problema por si só: por exemplo, pode fazer com que os dados antigos sejam processados duas vezes por outro sistema, em vez de serem substituídos por dados atualizados.
Uma grande parte do poder da linha de comando vem do fato de que, depois que você souber fazer algo na linha de comando, também implicitamente saberá como fazer isso acontecer automaticamente por meio de scripts . Mas isso só é verdade se os comandos que você usa interativamente também funcionarem exatamente da mesma maneira quando invocados em um contexto de script. Quaisquer diferenças significativas no comportamento entre uso interativo e uso de script criarão uma espécie de dissonância cognitiva que é irritante para um usuário avançado.
fonte
rm -rf
é tão eficaz, mesmo se você realmente não quer dizer para executá-lo em seu diretório home ...cp
vem do começo do Unix. Estava lá bem antes de o padrão Posix ser escrito. De fato: Posix acabou de formalizar o comportamento existente acp
esse respeito.Estamos falando de Epoch (01-01-1970), quando homens eram homens de verdade, mulheres eram mulheres de verdade e criaturinhas peludas ... (eu discordo). Naqueles dias, adicionar código extra tornava um programa maior. Esse era um problema, pois o primeiro computador que executava o Unix era o PDP-7 (atualizável para 144KB de RAM!). Então, as coisas eram pequenas, eficientes, sem recursos de segurança.
Então, naquela época, você tinha que saber o que estava fazendo, porque o computador simplesmente não tinha o poder de impedir que você fizesse qualquer coisa que se arrependesse mais tarde.
(Há um belo desenho animado de Zevar; pesquise "zevar cerveaux assiste par ordinateur" para encontrar a evolução do computador. Ou tente http://perinet.blogspirit.com/archive/2012/02/12/zevar-et- cointe.html enquanto existir)
Para aqueles realmente interessados (vi algumas especulações nos comentários): O original
cp
no primeiro Unix tinha cerca de duas páginas de código assembler (C veio mais tarde). A parte relevante foi:(Então, um duro
sys creat
)E, enquanto estamos nisso: Versão 2 do Unix usada (sniplet de código)
o que também é difícil
creat
sem testes ou salvaguardas. Observe que o código C do V2 Unixcp
é inferior a 55 linhas!fonte
cp
apenasopen
ed o destino comO_CREAT | O_TRUNC
e realizou umread
/write
ciclo; claro, com os modernoscp
existem tantos botões que ele basicamente precisa tentarstat
o destino com antecedência e pode facilmente verificar a existência primeiro (e faz comcp -i
/cp -n
), mas se as expectativas foram estabelecidas a partir decp
ferramentas originais e simples , mudando esse comportamento iria quebrar scripts existentes desnecessariamente. Afinal , não é como as conchas modernas quealias
não podem simplesmente tornarcp -i
o padrão para uso interativo.creat
equivale aopen
+O_CREAT | O_TRUNC
), mas a falta deO_EXCL
explica porque não seria tão fácil lidar com arquivos existentes; tentar fazer isso seria inerentemente atrevido (você basicamente teria queopen
/stat
verificar a existência e depois usá-locreat
, mas em grandes sistemas compartilhados, sempre é possível quando você chegacreat
, alguém criou o arquivo e agora de qualquer maneira). Também pode sobrescrever incondicionalmente.Como esses comandos também devem ser usados em scripts, possivelmente executando sem qualquer tipo de supervisão humana, e também porque há muitos casos em que você realmente deseja substituir o destino (a filosofia dos shells do Linux é que o humano sabe o que ela esta fazendo)
Ainda existem algumas salvaguardas:
cp
tem um-n
|--no-clobber
opçãocp
, reclamará que o último não é um diretório.fonte
Esse comentário parece uma pergunta sobre um princípio geral de design. Freqüentemente, perguntas sobre isso são muito subjetivas e não somos capazes de escrever uma resposta adequada. Esteja avisado de que podemos fechar perguntas neste caso.
Às vezes, temos uma explicação para a escolha do design original, porque os desenvolvedores escreveram sobre eles. Mas não tenho uma resposta tão boa para esta pergunta.
Por que
cp
é projetado dessa maneira?O problema é que o Unix tem mais de 40 anos.
Se você estava criando um novo sistema agora, poderá fazer diferentes escolhas de design. Mas mudar o Unix quebraria os scripts existentes, como mencionado em outras respostas.
Por que foi
cp
projetado para substituir silenciosamente os arquivos existentes?A resposta curta é "não sei" :-).
Entenda que
cp
é apenas um problema. Eu acho que nenhum dos programas de comando originais protegidos contra a substituição ou exclusão de arquivos. O shell tem um problema semelhante ao redirecionar a saída:Este comando também substitui silenciosamente
second.html
.Estou interessado em pensar em como todos esses programas poderiam ser redesenhados. Pode exigir alguma complexidade extra.
Eu acho que isso faz parte da explicação: o Unix inicial enfatizava implementações simples . Para uma explicação mais detalhada disso, consulte "pior é melhor", vinculado ao final desta resposta.
Você pode alterar
> second.html
para parar com um erro, sesecond.html
já existir. No entanto, como dissemos, por vezes, o usuário não deseja substituir um arquivo existente. Por exemplo, ela pode estar construindo um comando complexo, tentando várias vezes até que faça o que deseja.O usuário pode executar
rm second.html
primeiro se precisar. Este pode ser um bom compromisso! Possui algumas desvantagens possíveis.rm
. Então, eu gostaria de tornarrm
mais seguro também. Mas como? Serm
mostrarmos cada nome de arquivo e solicitarmos que o usuário confirme, agora ela precisará escrever três linhas de comandos em vez de uma. Além disso, se ela precisar fazer isso com muita frequência, ela adquirirá o hábito e digitar "y" para confirmar sem pensar. Por isso, pode ser muito chato e ainda pode ser perigoso.Em um sistema moderno, recomendo instalar o
trash
comando e usá-lo em vez derm
onde for possível. A introdução do armazenamento do Lixo foi uma ótima idéia, por exemplo, para um PC gráfico de usuário único .Eu acho que também é importante entender as limitações do hardware Unix original - RAM e espaço em disco limitados, saída exibida em impressoras lentas , bem como o sistema e o software de desenvolvimento.
Observe que o Unix original não tinha preenchimento de tabulação , para preencher rapidamente um nome de arquivo para um
rm
comando. (Além disso, o shell Bourne original não possui histórico de comandos, por exemplo, quando você usa a tecla de seta para cimabash
).Com a saída da impressora, você usaria o editor baseado em linha
ed
,. Isso é mais difícil de aprender do que um editor de texto visual. Você precisa imprimir algumas linhas atuais, decidir como deseja alterá-las e digitar um comando de edição.Usar
> second.html
é um pouco como usar um comando em um editor de linha. O efeito que isso depende depende do estado atual. (Sesecond.html
já existir, seu conteúdo será descartado). Se o usuário não tiver certeza do estado atual, é esperado que ele seja executadols
ouls second.html
primeiro."Implementação simples" como princípio de design
Existe uma interpretação popular do design do Unix, que começa:
fonte
cp
um "problema"? Tê-lo interativamente pedindo permissão ou falhar pode ser um "problema" tão grande quanto esse.cat first.html second.html > first.html
dar resultado emfirst.html
ser substituído pelo conteúdo desecond.html
apenas. O conteúdo original é perdido para sempre.O design do "cp" remonta ao design original do Unix. De fato, havia uma filosofia coerente por trás do design do Unix, que foi um pouco menos do que, de brincadeira, foi referido como Pior-é-Melhor * .
A idéia básica é que manter o código simples é realmente uma consideração de design mais importante do que ter uma interface perfeita ou "fazer a coisa certa".
( ênfase minha )
Lembrando que isso foi em 1970, o caso de uso de "Quero copiar este arquivo apenas se ele ainda não existir" teria sido um caso de uso bastante raro para alguém que está executando uma cópia. Se era isso que você queria, seria capaz de verificar antes da cópia, e isso pode até ser roteirizado.
Quanto ao motivo pelo qual um SO com essa abordagem de design foi o vencedor em todos os outros SOs que estavam sendo construídos na época, o autor do ensaio também tinha uma teoria para isso.
* - ou o que o autor, mas mais ninguém, chamou de "A abordagem de Nova Jersey" .
fonte
creat()
vsopen()
.open()
Não pôde criar um arquivo se ele não existisse. Leva apenas 0/1/2 para leitura / gravação / ambos. Ele não ainda tomarO_CREAT
, e não háO_EXCL
).A principal razão é que uma GUI é, por definição, interativa, enquanto uma binária
/bin/cp
é apenas um programa que pode ser chamado de todos os tipos de lugares, por exemplo, na sua GUI ;-). Aposto que ainda hoje a grande maioria das chamadas/bin/cp
não será de um terminal real com um usuário digitando um comando shell, mas de um servidor HTTP ou de um sistema de email ou de um NAS. Uma proteção interna contra erros do usuário faz todo sentido em um ambiente interativo; menos ainda em um binário simples. Por exemplo, sua GUI provavelmente chamará/bin/cp
o plano de fundo para executar as operações reais e terá que lidar com as questões de segurança na saída padrão, mesmo que apenas peça ao usuário!Observe que, desde o primeiro dia, era quase trivial escrever um invólucro seguro,
/bin/cp
se desejado. A filosofia * nix é fornecer blocos de construção simples para os usuários: um deles/bin/cp
é um deles.fonte