J'ai une collection de répertoires qui contiennent tous un fichier particulier qui porte le même nom dans tous les répertoires.
dir1/dirA/file.txt
dir1/dirB/file.txt
dir1/dirC/file.txt
....
dir4/dirX/file.txt
dir4/dirY/file.txt
dir4/dirZ/file.txt
Je souhaite copier ces fichiers dans un autre répertoire, de sorte que le nom de chaque fichier correspond au nom de son répertoire parent:
all_files/
dirA.txt
dirB.txt
dirC.txt
....
dirX.txt
dirY.txt
dirZ.txt
Bien que je comprenne que ces exemples peuvent entraîner des chevauchements, ce n'est pas un problème pour moi - je sais que tous les répertoires cibles ont des noms uniques.
J'utilise bash sous OS X. J'ai essayé de faire plusieurs choses comme celle-ci (voir ici et ici ). Ma pensée serait de scinder la chaîne sur les barres obliques, d’obtenir l’avant-dernière et de l’utiliser, mais je ne pouvais pas le faire fonctionner (en fonction ce et d'autres):
for name in `ls */*/file`
directory=${DIRS[${#DIRS[@]} - 2]}
mv name ../all_files/${directory}.txt
done
Cependant, je ne pouvais pas le faire fonctionner.
Réponses:
Certains commentaires:
Ne faites jamais ceci ou quelque chose comme ça:
Si les noms de fichiers comportent des espaces ou d’autres caractères difficiles, la procédure ci-dessus échouera. Utilisez plutôt:
Le shell gérera correctement ce qui précède, peu importe l'étrangeté du nom de fichier.
Cela souffre de plusieurs problèmes:
Plus important encore, cela déplacera le fichier littéralement nommé
name
. Vous voulez plutôt déplacer le fichier que lename
variable fait référence à. Pour cet usage"$name"
plutôt quename
. Notez l'utilisation de guillemets doubles ici. Cela protège le nom du fractionnement des mots afin que cela fonctionne même si le nom du fichier contient des espaces ou d'autres caractères difficiles.De même, l'emplacement de destination doit être entouré de guillemets doubles.
la source
J'y ai un peu réfléchi et j'ai trouvé deux solutions. Le premier utilise basename et dirname:
Celui-ci utilise le fractionnement de chaîne (comme je voulais le faire à l'origine)
J'espère que cela aide quelqu'un!
la source
--
aprèsbasename
etdirname
. Cette fonctionnalité n'est pas documentée sur mon système (linux) mais je vois que cela fonctionne.