C'est probablement très simple, mais je ne peux pas le comprendre. J'ai une structure de répertoires comme celle-ci (dir2 est à l'intérieur de dir1):
/dir1
/dir2
|
--- file1
|
--- file2
Quelle est la meilleure façon d'aplatir cette structure de directeur de manière à obtenir les fichiers file1 et file2 dans dir1 et non dir2.
Vous pouvez le faire avec GNU find
et GNU mv
:
find /dir1 -mindepth 2 -type f -exec mv -t /dir1 -i '{}' +
Fondamentalement, la façon dont cela fonctionne si ce find
parcourt l’arborescence complète du répertoire et pour chaque fichier (-type f
) qui ne se trouve pas dans le répertoire de niveau supérieur (-mindepth 2
), il exécute un mv
pour le déplacer vers le répertoire souhaité (-exec mv … +
). Le -t
argument à mv
vous permet de spécifier d'abord le répertoire de destination, ce qui est nécessaire car le +
forme de -exec
place tous les emplacements source à la fin de la commande. Le -i
fait mv
demander avant d'écraser les doublons; vous pouvez remplacer -f
pour les remplacer sans demander (ou -n
pour ne pas demander ou écraser).
Comme le souligne Stephane Chazelas, ce qui précède ne fonctionne qu'avec GNU (qui sont standard sur Linux, mais pas la plupart des autres systèmes). Ce qui suit est un peu plus lent (car il invoque mv
plusieurs fois) mais beaucoup plus universel:
find /dir1 -mindepth 2 -type f -exec mv -i '{}' /dir1 ';'
En zsh:
mv dir1/*/**/*(.D) dir1
**/
Parcourt les sous-répertoires récursivement. Le qualificatif glob.
Ne correspond qu'aux fichiers normaux et D
garantit que les fichiers dot sont inclus (par défaut, les fichiers dont le nom commence par un .
sont exclus des correspondances génériques). Pour nettoyer les répertoires désormais vides par la suite, exécutez rmdir dir1/**/*(/Dod)
- /
Restreint aux répertoires, et od
ordonne d'abord la profondeur des correspondances afin de supprimer dir1/dir2/dir3
avant dir1/dir2
.
Si la longueur totale des noms de fichiers est très grande, vous pouvez rencontrer une limitation de la longueur de la ligne de commande. Zsh a des fonctions intégrées pour mv
et rmdir
qui ne sont pas affectées par cette limitation: exécutez zmodload zsh/files
Pour les activer.
Avec uniquement des outils POSIX:
find dir1 -type f -exec mv {} dir1 \;
find dir1 -depth -exec rmdir {} \;
ou (plus rapide car il n'a pas à exécuter un processus distinct pour chaque fichier)
find dir1 -type f -exec sh -c 'mv "$@" dir1' _ {} +
find dir1 -depth -exec rmdir {} +
tar et Zip ont tous deux la possibilité d'incorporer puis de supprimer une structure de répertoire, j'ai donc pu aplatir rapidement un répertoire imbriqué avec
tar -cvf all.tar *
suivi de déplacer all.tar vers un nouvel emplacement puis
tar -xvf all.tar --strip=4
Essayez de faire ceci:
cp /dir1/dir2/file{1,2} /another/place
ou pour chaque fichier correspondant à file[0-9]*
dans le sous-répertoire:
cp /dir1/dir2/file[0-9]* /another/place
J'ai écrit deux fonctions que vous pouvez utiliser ensemble pour cela, vous pouvez limiter le niveau du répertoire en ajoutant un -maxdepth $VAL
paramètre.
# This scripts flattens the file directory
# Run this script with a folder as parameter:
# $ path/to/script path/to/folder
#!/bin/bash
rmEmptyDirs(){
local DIR="$1"
for dir in "$DIR"/*/
do
[ -d "${dir}" ] || continue # if not a directory, skip
dir=${dir%*/}
if [ "$(ls -A "$dir")" ]; then
rmEmptyDirs "$dir"
else
rmdir "$dir"
fi
done
if [ "$(ls -A "$DIR")" ]; then
rmEmptyDirs "$DIR"
fi
}
flattenDir(){
local DIR="$1"
find "$DIR" -mindepth 2 -type f -exec mv -i '{}' "$DIR" ';'
}
read -p "Do you wish to flatten folder: ${1}? " -n 1 -r
echo # (optional) move to a new line
if [[ $REPLY =~ ^[Yy]$ ]]
then
flattenDir "$1" &
rmEmptyDirs "$1" &
echo "Done";
fi
Développant la réponse populaire à cette question, car j'avais un cas d'utilisation pour aplatir un répertoire contenant des fichiers du même nom.
dir1/
├── dir2
│ └── file
└── dir3
└── file
Dans ce cas, l'option -i
(--interactive
) Passée à mv
ne donnerait pas le résultat souhaité pour aplatir la structure du répertoire et gérer les conflits de noms. Il est donc simplement remplacé par --backup=t
(Équivalent à --backup=numbered
). Plus de documentation sur l'option -b
(--backup
) Disponible sur https://www.gnu.org/software/coreutils/manual/coreutils.html#Backup-options =.
Résultant en:
find dir1/ -mindepth 2 -type f -exec mv -t dir1/ --backup=t '{}' +
Ce qui donne:
dir1/
├── dir2
├── dir3
├── file
└── file.~1~