web-dev-qa-db-fra.com

mv: Déplacer le fichier uniquement si la destination n'existe pas

Puis-je utiliser mv file1 file2 d'une manière qui ne bouge que file1 à file2 si file2 n'existe pas?

J'ai essayé

yes n | mv -i file1 file2

(cela permet à mv de demander si file2 doit être remplacé et de répondre automatiquement non) mais en plus d'abuser -i cela ne me donne pas non plus de bons codes d'erreur (toujours 141 au lieu de 0 si déplacé et autre chose s'il n'est pas déplacé)

51

mv -vn file1 file2. Cette commande fera ce que vous voulez. Vous pouvez ignorer -v si tu veux.

-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 fichier2 n'existe pas.

Veuillez noter cependant que ce n'est pas POSIX comme mentionné par ThomasDickey .

71
MatthewRock

mv -n

De man mv sur un système GNU:

-n, --no-clobber
n'écrase pas un fichier existant

Sur un système FreeBSD:

-n N'écrasez pas un fichier existant. (L'option -n remplace toutes les options -f ou -i précédentes.)

17
Dani_l
if [ ! -e file2 ] && [ ! -L file2 ]
then
    mv file1 file2
# else echo >&2 there is already a file2 file.
fi

Ou:

if ! ls -d file2 > /dev/null 2>&1
then
    mv file1 file2
fi

N'exécuterait que mv si file2 n'existe pas. Notez qu'il ne garantit pas qu'un file2 ne sera pas remplacé car un file2 aurait pu être créé entre le test et le mv, mais notez qu'au moins les versions actuelles de GNU mv avec -i ou -n ne donne pas non plus cette garantie (bien que la condition de concurrence y soit plus étroite puisque la vérification est effectuée dans mv).

À l'autre extrémité, il est portable, vous permet de faire la distinction entre les cas, et fonctionne quel que soit le type de file2 fichier (normal, pipe, pair répertoire).

10
Majenko

Une approche sans course avec GNU ln à condition que file1 Ne soit pas de type répertoire:

ln -PT file1 file2 && rm file1

(À l'exception des bogues dans certains systèmes de fichiers réseau), cela garantit qu'aucun fichier file2 Ne sera écrasé (ou que si file2 Est de type répertoire, file1 Ne sera pas déplacé dedans), car l'appel système link(), contrairement à l'appel système rename() échouera si la cible existe.

Cependant, il y aura un état intermédiaire où le fichier existe à la fois sous file1 Et file2.

L'option -T (Pour toujours faire une link("file1", "file2") même si file2 Est de type répertoire) est spécifique à GNU.

Vous pouvez également utiliser la commande link:

link file1 file2 && rm file1

Cependant, si file1 Est un lien symbolique, selon l'implémentation, file2 Sera soit un lien dur vers ce lien symbolique, soit vers la cible de ce lien symbolique (sur Solaris, utilisez /usr/sbin/link , pas /usr/xpg4/bin/link).

8
Stéphane Chazelas

Vous pouvez aussi utiliser test -e name qui retournera vrai si le nom existe (quel que soit le fichier, le répertoire ou le lien symbolique).

Par exemple:

touch file
mkdir dir
ln -s file symlink
test -e file && echo file exists
test -e dir && echo dir exists
test -e symlink && echo symlink exists
test -e file || echo you wont see this echo
test -e doesnotexist || echo doesnotexist does not exist...
0
H Briceno