¿Puedo utilizar mv file1 file2de una manera que sólo se mueve file1a file2si file2que no existe?
He intentado
yes n | mv -i file1 file2
(esto permite mvpreguntar si el archivo 2 debe ser anulado y automáticamente responde que no), pero además de abusar -i, tampoco me da buenos códigos de error (siempre 141 en lugar de 0 si se movió y algo más si no se movió)

pipefailopción activada ya que 141 sería el estado de salida deyes,mvque no tendría ninguna razón para obtener un SIGPIPE aquí.-Tpara eso.mvlugar del deyes, la solución más simple podría sermv -i file1 file2 < <(yes n)Respuestas:
mv -vn file1 file2. Este comando hará lo que quieras. Puedes saltarte-vsi quieres.-vlo hace detallado: mv le dirá que movió el archivo si lo mueve (útil, ya que existe la posibilidad de que el archivo no se mueva)-nse mueve solo si el archivo2 no existe.Sin embargo, tenga en cuenta que esto no es POSIX como lo menciona ThomasDickey .
fuente
stracemuestra que usa (en mi sistema): stat ("file2", 0x7ffe3e705d10) = -1 ENOENT (No existe tal archivo o directorio) lstat ("file1", {st_mode = S_IFREG | 0644, st_size = 0, ...}) = 0 lstat ("file2", 0x7ffe3e705a10) = -1 ENOENT (No existe tal archivo o directorio) renombrar ("file1", "file2") = 0 lseek (0, 0, SEEK_CUR) = -1 ESPIPE (búsqueda ilegal). Así que parece que se usa cambiar el nombre. La solución @ StéphaneChazelas parece ser la correcta si realmente quieres hacerlo sin carreras.renameat2mv -nDesde
man mvun sistema GNU:En un sistema FreeBSD:
fuente
O:
Solo se ejecutaría
mvsifile2no existe. Tenga en cuenta que no garantiza quefile2no se anule a porque sefile2podría haber creado entre la prueba y la pruebamv, pero tenga en cuenta que al menos las versiones actuales de GNUmvcon-io-nno dan esa garantía tampoco (aunque la condición de carrera es más estrecha allí ya que la verificación se realiza dentromv).Por otro lado, es portátil, le permite discriminar entre los casos y funciona independientemente del tipo de
file2archivo (regular, canalización, incluso directorio ).fuente
renameat2que le puedes dar unaRENAME_NOREPLACEbandera. Creo que esto comprueba atómicamente la existencia del archivo y luego lo mueve.Un enfoque libre de raza con GNU
lnproporcionadofile1no es del tipo directorio :(Excepto por errores en algunos sistemas de archivos de red), eso garantiza que ningún
file2archivo se anulará (o que sifile2es de tipo directorio,file1no se moverá a él), porque lalink()llamada al sistema, al contrario de larename()llamada del sistema, fallará si el El objetivo existe.Sin embargo, habrá un estado intermedio donde el archivo existe tanto como
file1yfile2.La
-Topción (hacer siempre un directoriolink("file1", "file2")aunquefile2sea de tipo) es específico de GNU.También puedes usar el
linkcomando:Sin embargo, si
file1es un enlace simbólico, dependiendo de la implementación,file2será un enlace directo a ese enlace simbólico o al destino de ese enlace simbólico (en Solaris, use/usr/sbin/link, not/usr/xpg4/bin/link).fuente
renameat2con banderaRENAME_NOREPLACEes atómica?También puede usar
test -e nameque devolverá verdadero si el nombre existe (independientemente del archivo, directorio o enlace simbólico).Por ejemplo:
fuente
ln -s doesnotexist exists; test -e exists || echo "does it really not exist?". Lo mismo con por ejemploln -s /var/spool/cron/crontabs/. exists(y no eres root ni miembro del grupo crontab).