338 votes

Y a-t-il un moyen de faire en sorte que mv crée le répertoire de destination s'il n'existe pas?

Alors, si je suis dans mon répertoire personnel et que je veux déplacer foo.c vers ~/bar/baz/foo.c, mais que ces répertoires n'existent pas, y a-t-il un moyen de créer automatiquement ces répertoires, de sorte que vous auriez seulement à taper

mv foo.c ~/bar/baz/ 

et tout se passerait bien ? Il semble que vous pourriez alias mv à un simple script bash qui vérifierait si ces répertoires existaient et, le cas échéant, appellerait mkdir puis mv, mais je voulais vérifier si quelqu'un avait une meilleure idée.

0 votes

349voto

KarstenF Points 1361

Et que pensez-vous de cette astuce en une seule ligne (en bash) :

mkdir --parents ./some/path/; mv yourfile.txt $_

Expliquons cela en détail :

mkdir --parents ./some/path
# si cela ne fonctionne pas, essayez
mkdir -p ./some/path

crée le répertoire (y compris tous les répertoires intermédiaires), après quoi :

mv yourfile.txt $_

déplace le fichier dans ce répertoire ($_ se développe en le dernier argument passé à la commande shell précédente, c'est-à-dire le répertoire nouvellement créé).

Je ne suis pas sûr dans quelle mesure cela fonctionnera dans d'autres shells, mais cela pourrait vous donner des idées sur ce à quoi il faut prêter attention.

Voici un exemple utilisant cette technique :

$ > ls
$ > touch yourfile.txt
$ > ls
yourfile.txt
$ > mkdir --parents ./some/path/; mv yourfile.txt $_
$ > ls -F
some/
$ > ls some/path/
yourfile.txt

1 votes

D'accord, mais c'est une solution moins générale. Ma solution pourrait servir de substitut mv (donc un alias dans bash) (en supposant qu'elle fonctionne correctement -- toujours non testée!).

1 votes

Pourquoi cette obsession avec le ./ redondant partout ? Les args ne sont pas des commandes dans le chemin sans le répertoire ....

7 votes

Pour les débutants, -parents peut être raccourci en -p

73voto

Billmc Points 71
mkdir -p `dirname /destination/moved_file_name.txt`  
mv /full/path/the/file.txt  /destination/moved_file_name.txt

3 votes

Je suis le seul à réaliser que ce code n'a aucun sens? Vous créez de manière récursive le chemin absolu vers le fichier existant (ce qui signifie que ce chemin existe déjà) et puis vous déplacez le fichier vers un emplacement (qui, dans votre exemple, n'existe pas).

4 votes

@user544262772 Le dirname de GNU coreutils n'exige pas que son argument existe, c'est une simple manipulation de chaîne. Je ne peux pas parler pour d'autres distributions. Rien de mal avec ce code à première vue.

0 votes

Voici la réponse qui est la plus facile à automatiser, je pense. pour f in *.txt; faire mkdir -p `dirname /destination/${f//regex/repl}`; mv "$f" "/destination/${f//regex/repl}" ; fait

26voto

Sepero Points 734

Enregistrez en tant que script nommé mv.sh

#!/bin/bash
# mv.sh
dir="$2" # Inclure un / à la fin pour indiquer le répertoire (pas le nom de fichier)
tmp="$2"; tmp="${tmp: -1}"
[ "$tmp" != "/" ] && dir="$(dirname "$2")"
[ -a "$dir" ] ||
mkdir -p "$dir" &&
mv "$@"

Ou placez-le à la fin de votre fichier ~/.bashrc en tant que fonction qui remplace la commande mv par défaut sur chaque nouveau terminal. Utiliser une fonction permet à bash de le garder en mémoire, au lieu de devoir lire un fichier de script à chaque fois.

function mvp ()
{
    dir="$2" # Inclure un / à la fin pour indiquer le répertoire (pas le nom de fichier)
    tmp="$2"; tmp="${tmp: -1}"
    [ "$tmp" != "/" ] && dir="$(dirname "$2")"
    [ -a "$dir" ] ||
    mkdir -p "$dir" &&
    mv "$@"
}

Exemple d'utilisation:

mv.sh fichier ~/Téléchargements/some/new/path/ # <- Terminer par un slash

Basé sur la contribution de Chris Lutz.

3 votes

Cela répond le plus précisément à la question à mon avis. L'utilisateur souhaite une commande mv améliorée. Particulièrement utile pour les scripts, c'est-à-dire que vous ne voulez pas nécessairement exécuter les vérifications et exécuter mkdir -p à chaque fois que vous avez besoin d'utiliser mv. Mais comme je voudrais avoir le comportement par défaut en cas d'erreur pour mv, j'ai changé le nom de la fonction en mvp -- afin de savoir quand je pourrais être en train de créer des répertoires.

0 votes

Il semble que ce soit la meilleure idée de solution, mais l'implémentation plante souvent.

2 votes

@UlisesLayera J'ai modifié l'algorithme pour le rendre plus robuste. Il ne devrait plus planter maintenant.

14voto

strager Points 41713

Vous pouvez utiliser mkdir :

mkdir -p ~/bar/baz/ && \
mv foo.c ~/bar/baz/

Un script simple pour le faire automatiquement (non testé) :

#!/bin/sh

# Récupérer le dernier argument (argument numéro $#)    
eval LAST_ARG=\$$#

# Supprimer le nom de fichier (si existant) de la destination, obtenir le répertoire
DIR_NAME=`echo $2 | sed -e 's_/[^/]*$__'`

# Se déplacer dans le répertoire, en créant le répertoire si nécessaire
mkdir -p "$DIR_NAME" || exit
mv "$@"

0 votes

Lorsque j'exécute "$ dirname ~?bar/baz/", j'obtiens "/home/dmckee/bar", ce qui n'est pas ce que vous voulez ici...

0 votes

@dmckee, Ah, tu as raison. Une idée sur comment résoudre cela? Si vous entrez ~/bar/baz, vous voulez soit (a) copier vers ~/bar/ et renommer en baz, soit (b) copier vers ~/bar/baz/. Quel est le meilleur outil pour cela?

0 votes

@dmckee, J'ai utilisé regexp/sed pour trouver une solution. Est-ce que cela vous convient? =]

2voto

Blarn Blarnson Points 1

Manière plus ridicule, mais fonctionnelle :

mkdir -p $2
rmdir $2
mv $1 $2

Créez le répertoire avec mkdir -p en incluant un répertoire temporaire portant le nom du fichier de destination, puis supprimez ce répertoire portant le nom du fichier avec un simple rmdir, puis déplacez votre fichier vers sa nouvelle destination. Je pense que la réponse en utilisant dirname est probablement la meilleure cependant.

0 votes

Oui, un peu ridicule.:-) Si $2 est un répertoire (comme dans la question initiale), alors il échoue misérablement, car le dernier répertoire sera supprimé, donc le 'mv' échouera. Et si $2 existe déjà alors il essaie également de le supprimer.

0 votes

Merci! C'est exactement ce dont j'avais besoin d'accomplir : mv ./old ./subdir/new où le sous-répertoire n'existe pas encore

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X