Probé cp
con los siguientes comandos:
$ ls
first.html second.html third.html
$ cat first.html
first
$ cat second.html
second
$ cat third.html
third
Luego copio first.html
a second.html
:
$ cp first.html second.html
$ cat second.html
first
El archivo second.html
se sobrescribe en silencio sin ningún error. Sin embargo, si lo hago en una GUI de escritorio arrastrando y soltando un archivo con el mismo nombre, se agregará el sufijo first1.html
automáticamente. Esto evita sobrescribir accidentalmente un archivo existente.
¿Por qué no cp
sigue este patrón en lugar de sobrescribir archivos en silencio?
cp
acp -i
o similares, ya se acostumbrará a tener una red de seguridad, por lo que los sistemas en los que no está disponible (la mayoría de ellos) que mucho más arriesgado. Es mejor que te enseñes a ti mismo rutinariamente,cp -i
etc., si eso es lo que prefieres.Respuestas:
El comportamiento predeterminado de sobrescritura de
cp
se especifica en POSIX.Cuando se escribió la especificación POSIX, ya existía una gran cantidad de scripts, con una suposición incorporada para el comportamiento de sobrescritura predeterminado. Muchos de esos scripts fueron diseñados para ejecutarse sin la presencia directa del usuario, por ejemplo, como trabajos cron u otras tareas en segundo plano. Cambiar el comportamiento los habría roto. Revisarlos y modificarlos todos para agregar una opción para forzar la sobrescritura donde sea necesario probablemente se consideró una tarea enorme con beneficios mínimos.
Además, la línea de comandos de Unix siempre se diseñó para permitir que un usuario experimentado trabaje eficientemente, incluso a expensas de una curva de aprendizaje difícil para un principiante. Cuando el usuario ingresa un comando, la computadora debe esperar que el usuario realmente lo diga en serio, sin ninguna duda; Es responsabilidad del usuario tener cuidado con los comandos potencialmente destructivos.
Cuando se desarrolló el Unix original, los sistemas tenían tan poca memoria y almacenamiento masivo en comparación con las computadoras modernas que sobrescriben las advertencias y los avisos que probablemente se consideraron lujos innecesarios y derrochadores.
Cuando se estaba escribiendo el estándar POSIX, el precedente estaba firmemente establecido, y los escritores del estándar eran muy conscientes de las virtudes de no romper la compatibilidad con versiones anteriores .
Además, como otros han descrito, cualquier usuario puede agregar / habilitar esas funciones para sí mismo, utilizando alias de shell o incluso creando un
cp
comando de reemplazo y modificando su$PATH
para encontrar el reemplazo antes del comando del sistema estándar, y obtener la red de seguridad de esa manera si deseado.Pero si lo hace, descubrirá que está creando un peligro para usted. Si el
cp
comando se comporta de una manera cuando se usa de manera interactiva y de otra manera cuando se lo llama desde un script, es posible que no recuerde que existe la diferencia. En otro sistema, puede terminar siendo descuidado porque está acostumbrado a las advertencias y avisos en su propio sistema.Si el comportamiento en las secuencias de comandos aún coincidirá con el estándar POSIX, es probable que se acostumbre a las indicaciones en el uso interactivo, luego escriba una secuencia de comandos que haga algunas copias masivas y luego descubra que está sobrescribiendo algo sin darse cuenta.
Si aplica la solicitud en los scripts también, ¿qué hará el comando cuando se ejecute en un contexto que no tenga ningún usuario, por ejemplo, procesos en segundo plano o trabajos cron? ¿Se bloqueará, cancelará o sobrescribirá el script?
Colgar o abortar significa que una tarea que se suponía que debía hacerse automáticamente no se realizará. No sobrescribir a veces también puede causar un problema en sí mismo: por ejemplo, puede hacer que los datos antiguos sean procesados dos veces por otro sistema en lugar de ser reemplazados por datos actualizados.
Una gran parte del poder de la línea de comando proviene del hecho de que una vez que sepa cómo hacer algo en la línea de comando, implícitamente también sabrá cómo hacer que suceda automáticamente mediante secuencias de comandos . Pero eso solo es cierto si los comandos que usa de forma interactiva también funcionan exactamente igual cuando se invocan en un contexto de script. Cualquier diferencia significativa en el comportamiento entre el uso interactivo y el uso programado creará una especie de disonancia cognitiva que es molesta para un usuario avanzado.
fuente
rm -rf
es tan efectivo, incluso si realmente no quisiste ejecutarlo en tu directorio personal ...cp
viene del comienzo de Unix. Estaba allí mucho antes de que se escribiera el estándar Posix. De hecho: Posix acaba de formalizar el comportamiento existentecp
a este respecto.Estamos hablando de la época (1970-01-01), cuando los hombres eran hombres de verdad, las mujeres eran mujeres de verdad y pequeñas criaturas peludas ... (estoy divagando). En esos días, agregar código adicional hacía que un programa fuera más grande. Ese fue un problema entonces, porque la primera computadora que ejecutó Unix fue una PDP-7 (¡actualizable a 144 KB de RAM!). Así que las cosas eran pequeñas, eficientes, sin características de seguridad.
Entonces, en esos días, tenía que saber lo que estaba haciendo, porque la computadora simplemente no tenía el poder para evitar que hiciera algo de lo que luego se arrepintió.
(Hay una bonita caricatura de Zevar; busque "zevar cerveaux assiste par ordinateur" para encontrar la evolución de la computadora. O pruebe http://perinet.blogspirit.com/archive/2012/02/12/zevar-et- cointe.html durante el tiempo que exista)
Para aquellos realmente interesados (vi algunas especulaciones en los comentarios): El original
cp
en el primer Unix era sobre dos páginas de código ensamblador (C vino más tarde). La parte relevante fue:(Entonces, un duro
sys creat
)Y, mientras estamos en eso: se utilizó la versión 2 de Unix (fragmento de código)
que también es difícil
creat
sin pruebas ni salvaguardas. ¡Tenga en cuenta que el código C para V2 Unixcp
es de menos de 55 líneas!fuente
cp
solo editaropen
el destino conO_CREAT | O_TRUNC
y realizar unread
/write
loop; Claro, con las modernascp
perillas hay tantos botones que básicamente tiene que intentar llegar alstat
destino de antemano, y podría verificar fácilmente la existencia primero (y lo hace concp -i
/cp -n
), pero si las expectativas se establecieran a partir decp
herramientas originales y básicas , cambiar ese comportamiento rompería los scripts existentes innecesariamente. No es como si los shells modernosalias
no pudieran simplemente sercp -i
el predeterminado para el uso interactivo después de todo.creat
resulta ser equivalente aopen
+O_CREAT | O_TRUNC
), pero la falta deO_EXCL
explica por qué no hubiera sido tan fácil manejar los archivos existentes; tratar de hacerlo sería intrínsecamente picante (básicamente tendría queopen
/stat
verificar la existencia, luego usarcreat
, pero en sistemas compartidos grandes, siempre es posible cuando llega el momentocreat
, alguien más hizo el archivo y ahora ha volado) de todos modos). También podría sobrescribir incondicionalmente.Debido a que estos comandos también están destinados a ser utilizados en scripts, posiblemente ejecutados sin ningún tipo de supervisión humana, y también porque hay muchos casos en los que realmente desea sobrescribir el objetivo (la filosofía de los shells de Linux es que el humano sabe qué ella está haciendo)
Todavía hay algunas salvaguardas:
cp
tiene un-n
|--no-clobber
opcióncp
se quejará de que el último no es un directorio.fuente
Este comentario suena como una pregunta sobre un principio de diseño general. A menudo, las preguntas sobre estos son muy subjetivas, y no podemos escribir una respuesta adecuada. Tenga en cuenta que podemos cerrar preguntas en este caso.
A veces tenemos una explicación para la elección del diseño original, porque los desarrolladores han escrito sobre ellas. Pero no tengo una buena respuesta para esta pregunta.
¿Por qué
cp
está diseñado de esta manera?El problema es que Unix tiene más de 40 años.
Si estuviera creando un nuevo sistema ahora, podría hacer diferentes elecciones de diseño. Pero cambiar Unix rompería los scripts existentes, como se menciona en otras respuestas.
¿Por qué se
cp
diseñó para sobrescribir silenciosamente los archivos existentes?La respuesta corta es "No sé" :-).
Comprende que ese
cp
es solo un problema. Creo que ninguno de los programas de comando originales está protegido contra la sobrescritura o eliminación de archivos. El shell tiene un problema similar al redirigir la salida:Este comando también sobrescribe en silencio
second.html
.Me interesa pensar cómo se podrían rediseñar todos estos programas. Puede requerir cierta complejidad adicional.
Creo que esto es parte de la explicación: los primeros Unix enfatizaron implementaciones simples . Para una explicación más detallada de esto, vea "peor es mejor", vinculado al final de esta respuesta.
Puede cambiar
> second.html
para que se detenga con un error, sisecond.html
ya existe. Sin embargo, como hemos mencionado, a veces el usuario no desea reemplazar un archivo existente. Por ejemplo, puede estar construyendo un comando complejo, intentando varias veces hasta que haga lo que quiere.El usuario podría correr
rm second.html
primero si lo necesita. ¡Esto podría ser un buen compromiso! Tiene algunas posibles desventajas propias.rm
. Así que me gustaría hacerrm
más seguro también. ¿Pero cómo? Si hacemosrm
mostrar cada nombre de archivo y le pedimos al usuario que confirme, ahora tiene que escribir tres líneas de comandos en lugar de una. Además, si tiene que hacer esto con demasiada frecuencia, se acostumbrará y escribirá "y" para confirmar sin pensar. Por lo tanto, podría ser muy molesto y aún podría ser peligroso.En un sistema moderno, recomiendo instalar el
trash
comando y usarlo en lugar derm
donde sea posible. La introducción del almacenamiento de basura fue una gran idea, por ejemplo, para una PC gráfica de usuario único .Creo que también es importante comprender las limitaciones del hardware original de Unix: RAM y espacio en disco limitados, salida mostrada en impresoras lentas , así como el sistema y el software de desarrollo.
Observe que el Unix original no tenía finalización de tabulación , para completar rápidamente un nombre de archivo para un
rm
comando. (Además, el shell Bourne original no tiene historial de comandos, por ejemplo, como cuando usa la tecla de flecha hacia arribabash
).Con la salida de impresora, se usaría editor basado en línea,
ed
. Esto es más difícil de aprender que un editor de texto visual. Debe imprimir algunas líneas actuales, decidir cómo desea cambiarlas y escribir un comando de edición.Usar
> second.html
es un poco como usar un comando en un editor de línea. El efecto que tiene depende del estado actual. (Sisecond.html
ya existe, su contenido será descartado). Si el usuario no está seguro del estado actual, se espera que se ejecutels
o quels second.html
primero."Implementación simple" como principio de diseño
Hay una interpretación popular del diseño de Unix, que comienza:
fuente
cp
un "problema"? Hacer que interactivamente solicite permiso o que falle puede ser un "problema" tan grande como ese.cat first.html second.html > first.html
, dará como resultado quefirst.html
se sobrescriba solo con el contenidosecond.html
. El contenido original se pierde para siempre.El diseño de "cp" se remonta al diseño original de Unix. De hecho, había una filosofía coherente detrás del diseño de Unix, que ha sido un poco menos de lo que se ha referido en tono de broma como Peor-es-Mejor * .
La idea básica es que mantener el código simple es en realidad una consideración de diseño más importante que tener una interfaz perfecta o "hacer lo correcto".
( énfasis mío )
Recordando que esto era 1970, el caso de uso de "Quiero copiar este archivo solo si aún no existe" habría sido un caso de uso bastante raro para alguien que realiza una copia. Si eso es lo que querías, serías capaz de verificar antes de la copia, y eso incluso puede ser programado.
En cuanto a por qué un sistema operativo con ese enfoque de diseño resultó ser el que ganó a todos los demás sistemas operativos que se construyeron en ese momento, el autor del ensayo también tenía una teoría para eso.
* - o lo que el autor, pero nadie más, llamó "El enfoque de Nueva Jersey" .
fuente
creat()
vsopen()
.open()
No ha podido crear un archivo si no existiera. Sólo se necesita 0/1/2 para lectura / escritura / ambas cosas. No adoptan, sin embargoO_CREAT
, y no hayO_EXCL
)La razón principal es que una GUI es, por definición, interactiva, mientras que un binario como
/bin/cp
es solo un programa al que se puede llamar desde todo tipo de lugares, por ejemplo desde su GUI ;-). Apuesto a que incluso hoy la gran mayoría de las llamadas/bin/cp
no serán desde un terminal real con un usuario escribiendo un comando de shell, sino desde un servidor HTTP o un sistema de correo o un NAS. Una protección incorporada contra errores del usuario tiene mucho sentido en un entorno interactivo; menos en un binario simple. Por ejemplo, lo más probable es que su GUI llame/bin/cp
en segundo plano para realizar las operaciones reales y ¡tenga que ocuparse de las preguntas de seguridad en la salida estándar a pesar de que solo le preguntó al usuario!Tenga en cuenta que fue desde el primer día casi trivial escribir un envoltorio seguro
/bin/cp
si así lo desea. La filosofía * nix es proporcionar bloques de construcción simples para los usuarios: de estos,/bin/cp
es uno.fuente