Puis - je utiliser mv file1 file2
d'une manière qu'il ne se déplace file1
à file2
si file2
n'existe pas?
J'ai essayé
yes n | mv -i file1 file2
(cela permet de mv
demander si le fichier 2 doit être remplacé et de répondre automatiquement non), mais en plus de l'abuser, -i
cela ne me donne pas non plus de codes d'erreur intéressants (toujours 141 au lieu de 0 s'il est déplacé et autre chose s'il n'est pas déplacé)
pipefail
option 141, car le statut de sortie est définiyes
, pasmv
ce qui n'aurait aucune raison d'obtenir un SIGPIPE ici.-T
pour cela.mv
plutôt que celui deyes
, la solution la plus simple pourrait êtremv -i file1 file2 < <(yes n)
Réponses:
mv -vn file1 file2
. Cette commande fera ce que vous voulez. Vous pouvez sauter-v
si vous voulez.-v
le rend verbeux - mv vous dira qu'il a déplacé le fichier s'il le déplace (utile, car il est possible que le fichier ne soit pas déplacé)-n
se déplace uniquement si le fichier 2 n'existe pas.S'il vous plaît noter cependant que ce n'est pas POSIX comme mentionné par ThomasDickey .
la source
strace
montre qu’il utilise (sur mon système): stat ("fichier2", 0x7ffe3e705d10) = -1 ENOENT (aucun fichier ou répertoire de ce type) lstat ("fichier1", {st_mode = S_IFREG | 0644, st_size = 0, ...}) = 0 lstat ("fichier2", 0x7ffe3e705a10) = -1 ENOENT (aucun fichier ou répertoire de ce type) renommer ("fichier1", "fichier2") = 0 lseek (0, 0, SEEK_CUR) = -1 ESPIPE (recherche illégale). Alors renommer semble être utilisé. La solution @ StéphaneChazelas semble être la bonne si vous voulez vraiment faire la course gratuitement.renameat2
mv -n
Depuis
man mv
un système GNU:Sur un système FreeBSD:
la source
Ou:
Ne fonctionnerait que
mv
sifile2
n'existe pas. Notez que cela ne garantit pas qu’unfile2
ne sera pas annulé car unfile2
aurait pu être créé entre le test et lemv
, mais notez au moins que les versions actuelles de GNUmv
avec-i
ou-n
ne donnent pas cette garantie non plus (bien que la condition de concurrence soit plus étroite là-bas puisque le contrôle est fait à l'intérieurmv
).De l’autre côté, il est portable, vous permet de discriminer les cas et fonctionne quel que soit le type de
file2
fichier (normal, canal, répertoire ).la source
renameat2
que vous pouvez donner unRENAME_NOREPLACE
drapeau. Je crois que cela vérifie de manière atomique l'existence du fichier, puis le déplace.Une approche sans course avec GNU
ln
fourniefile1
n’est pas du type répertoire :(Sauf pour les bogues dans certains systèmes de fichiers réseau), cela garantit qu'aucun
file2
fichier ne sera remplacé (ou que s'ilfile2
est de type répertoire,file1
il ne sera pas déplacé dans celui-ci), car l'link()
appel système, contrairement à l'rename()
appel système, échouera si la la cible existe.Cependant, il y aura un état intermédiaire où le fichier existe en tant que
file1
etfile2
.L'
-T
option (toujours faire unlink("file1", "file2")
même sifile2
est de type répertoire) est spécifique à GNU.Vous pouvez également utiliser la
link
commande:Toutefois, si
file1
est un lien symbolique, en fonction de la mise en œuvre, ilfile2
s'agira soit d'un lien dur vers ce lien symbolique, soit vers la cible de ce lien symbolique (sous Solaris, utilisez/usr/sbin/link
ou non/usr/xpg4/bin/link
).la source
renameat2
avec drapeauRENAME_NOREPLACE
est atomique?Vous pouvez également utiliser
test -e name
qui renverra true si le nom existe (quels que soient le fichier, le répertoire ou le lien symbolique).Par exemple:
la source
ln -s doesnotexist exists; test -e exists || echo "does it really not exist?"
. Même chose avec par exempleln -s /var/spool/cron/crontabs/. exists
(et vous n'êtes ni root ni membre du groupe crontab).