Comment déplacer tous les fichiers d'un répertoire (y compris ceux cachés) vers un autre répertoire?
Par exemple, si j'ai un dossier "Foo" avec les fichiers ".hidden" et "notHidden" à l'intérieur, comment déplacer les deux fichiers dans un répertoire nommé "Bar"? Ce qui suit ne fonctionne pas, car le fichier ".hidden" reste dans "Foo".
mv Foo/* Bar/
Essayez-le vous-même.
mkdir Foo
mkdir Bar
touch Foo/.hidden
touch Foo/notHidden
mv Foo/* Bar/
mv Foo/*(DN) Bar/
ou
setopt -s glob_dots
mv Foo/*(N) Bar/
(Oubliez le (N)
si vous savez que le répertoire n'est pas vide.)
shopt -s dotglob nullglob
mv Foo/* Bar/
Si vous savez que le répertoire n'est pas vide:
FIGNORE='.?(.)'
mv Foo/* Bar/
for x in Foo/* Foo/.[!.]* Foo/..?*; do
if [ -e "$x" ]; then mv -- "$x" Bar/; fi
done
Si vous êtes prêt à laisser la commande mv
retourner un état d'erreur même si elle a réussi, c'est beaucoup plus simple:
mv Foo/* Foo/.[!.]* Foo/..?* Bar/
find Foo/ -mindepth 1 -maxdepth 1 -exec mv -t Bar/ -- {} +
Si cela ne vous dérange pas de passer au répertoire source:
cd Foo/ &&
find . -name . -o -exec sh -c 'mv -- "$@" "$0"' ../Bar/ {} + -type d -Prune
Voici plus de détails sur le contrôle de la correspondance des fichiers dot dans bash, ksh93 et zsh.
Définissez l'option dotglob
.
$ echo *
none zero
$ shopt -s dotglob
$ echo *
..two .one none zero
Il y a aussi la variable GLOBIGNORE
plus flexible , que vous pouvez définir sur une liste de motifs génériques séparés par deux-points à ignorer. S'il n'est pas défini (le paramètre par défaut), le shell se comporte comme si la valeur était vide si dotglob
est définie, et comme si la valeur était .*
si l'option est non définie. Voir Extension du nom de fichier dans le manuel. Les répertoires omniprésents .
et ..
sont toujours omis, sauf si le .
correspond explicitement au modèle.
$ GLOBIGNORE='n*'
$ echo *
..two .one zero
$ echo .*
..two .one
$ unset GLOBIGNORE
$ echo .*
. .. ..two .one
$ GLOBIGNORE=.:..
$ echo .*
..two .one
Définissez la variable FIGNORE
. S'il n'est pas défini (paramètre par défaut), le shell se comporte comme si la valeur était .*
. Pour ignorer .
et ..
, ils doivent être mis en correspondance explicitement (le manuel de ksh 93s + 2008-01-31 indique que .
et ..
sont toujours ignorés, mais cela ne décrit pas correctement le comportement réel).
$ echo *
none zero
$ FIGNORE='@(.|..)'
$ echo *
..two .one none zero
$ FIGNORE='n*'
$ echo *
. .. ..two .one zero
Vous pouvez inclure des fichiers de points dans un motif en les faisant correspondre explicitement.
$ unset FIGNORE
$ echo @(*|.[^.]*|..?*)
..two .one none zero
Pour que l'extension sorte vide si le répertoire est vide, utilisez l'option de correspondance de modèle N
: ~(N)@(*|.[^.]*|..?*)
ou ~(N:*|.[^.]*|..?*)
.
Définissez l'option dot_glob
.
% echo *
none zero
% setopt dot_glob
% echo *
..two .one none zero
.
et ..
ne sont jamais mis en correspondance, même si le modèle correspond explicitement au .
de tête.
% echo .*
..two .one
Vous pouvez inclure des fichiers de points dans un modèle spécifique avec le qualificatif D
glob .
% echo *(D)
..two .one none zero
Ajoutez le qualificatif N
glob pour que l'expansion soit vide dans un répertoire vide: *(DN)
.
Remarque: vous pouvez obtenir des résultats d'extension de nom de fichier dans différents ordres (par exemple, none
suivi de .one
suivi de ..two
) en fonction de vos paramètres de LC_COLLATE
, LC_ALL
et LANG
variables.
#!/bin/bash
shopt -s dotglob
mv Foo/* Bar/
man bash
dotglob S'il est défini, bash inclut les noms de fichiers commençant par un '.' dans les résultats de l'expansion du nom de chemin.
Un moyen simple de le faire dans bash
est
mv {Foo/*,Foo/.*} Bar/
Mais cela déplacera également les répertoires.
Si vous souhaitez déplacer tous les fichiers, y compris cachés, mais que vous ne voulez déplacer aucun répertoire, vous pouvez utiliser une boucle for et un test.
for i in $(ls -d {Foo/*,Foo/.*});do test -f $i && mv -v $i Bar/; done;
Une façon consiste à utiliser find
:
find Foo/ -type f -exec mv -t Bar/ {} \+
Le -type f
limite la commande find à la recherche de fichiers. Vous devriez enquêter sur le -type
, -maxdepth
, et -mindepth
options de find
pour personnaliser votre commande en fonction des sous-répertoires. Find a une longue mais très utile page de manuel .
Essayez la commande de copie cp
:
$ cp -r myfolder/* destinationfolder
cp -r
signifie copier récursif, donc tous les dossiers et fichiers seront copiés.
Vous pouvez utiliser la commande de suppression rm
pour supprimer un dossier:
$ rm -r myfolder
Voir plus: déplacer tous les fichiers d'un répertoire vers un autre .
Pour les distributions Linux minimales , ce qui suit devrait fonctionner. Tout d'abord, effectuez un mouvement de base tout (qui manque les fichiers cachés). Ensuite, déplacez tous les fichiers cachés (y compris le .
et ..
qui sera pas réellement déplacé).
mv /sourceDir/* /destinationDir 2> /dev/null
mv /sourceDir/.* /destinationDir 2> /dev/null
Notes: S'il n'y a pas de contenu visible, la première commande produira un message d'erreur. La deuxième commande toujours produira une erreur indiquant qu'elle ne peut pas se déplacer .
et ..
. En tant que tel, canalisez simplement les erreurs dans /dev/null
(comme montré).
Si vous en avez besoin comme doublure, combinez-les simplement avec un point-virgule:
mv /sourceDir/* /destinationDir 2> /dev/null; mv /sourceDir/.* /destinationDir 2> /dev/null
Rsync est une autre option:
rsync -axvP --remove-source-files sourcedirectory/ targetdirectory
Cela fonctionne car dans rsync, la barre oblique de fin est importante, sourcedirectory/
fait référence au contenu du répertoire, tandis que sourcedirectory
fait référence au répertoire lui-même.
L'inconvénient de cette méthode est que rsync ne nettoiera que les fichiers après le déplacement, pas le répertoire. Il vous reste donc une arborescence de répertoires d'origine vide. Pour des solutions de contournement, voir:
Déplacer des fichiers et supprimer des répertoires avec rsync?
Ainsi, bien que cela ne soit pas optimal pour les opérations de déplacement, il peut être extrêmement utile pour les opérations de copie.
Réponse pour bash/fish
Voici un moyen de le faire à l'aide de caractères génériques:
.[!.]* ..?*
correspondra tous les fichiers cachés sauf .
et ..
.[!.]* ..?* *
correspondra tous les fichiers (masqués ou non) sauf .
et ..
Et pour répondre à l'exemple particulier de cette question, vous avez besoin de cd foo && mv .[!.]* ..?* * ../bar
Explication
.[!.]*
correspond aux noms de fichiers commençant par un point, suivi par n'importe quel caractère sauf le point éventuellement suivi par n'importe quelle chaîne. C'est assez proche mais il manque des fichiers commençant par deux points comme ..foo
. Pour inclure de tels fichiers, nous ajoutons ..?*
qui correspond aux noms de fichiers commençant par deux points, suivis de n'importe quel caractère, éventuellement suivi de n'importe quelle chaîne.
Test
Vous pouvez tester ces caractères génériques avec les commandes ci-dessous. Je les ai essayés avec succès sous bash et fish. Ils échouent sous sh, zsh, xonsh.
mkdir temp
cd temp
touch a .b .bc ..c ..cd ...d ...de
ls .[!.]* ..?*
# you get this output:
.b .bc ..c ..cd ...d ...de
# cleanup
cd ..
rm -rf temp
Je trouve que cela fonctionne bien pour bash et il n'est pas nécessaire de modifier les options Shell
mv sourcedir/{*,.[^.]*} destdir/
ÉDITER:
Donc, comme l'a déclaré G-man, ma réponse d'origine n'est pas conforme au posix et est à peu près la même que la réponse de ndemou ci-dessus avec un changement, qui consiste à utiliser l'expansion d'accolade pour créer des listes de chaînes qui sont ensuite mises à exécution. Cela signifie simplement que vous n'avez pas besoin de cd
dans le répertoire source. Pas vraiment un grand changement, mais c'est différent.
exemple: supposons que vous ayez déjà la disposition suivante.
$ tree -a
.
├── destdir
└── sourcedir
├── ..d1
├── ..d2
├── ..double
├── file-1
├── file-2
├── .hidden-1
├── .hidden-2
├── ...t1
└── ...t2
La question d'origine ne mentionnait que les fichiers cachés avec une seule période, mais disons qu'il y en a avec deux ou plusieurs périodes au début du nom. Vous pouvez simplement ajouter une expression supplémentaire dans les accolades. On peut alors exécuter
mv sourcedir/{*,.[!.]*,..?*} destdir/
Cela se développe comme suit:
mv sourcedir/file-1 sourcedir/file-2 sourcedir/.hidden-1 sourcedir/.hidden-2 sourcedir/..d1 sourcedir/..d2 sourcedir/..double sourcedir/...t1 sourcedir/...t2 destdir/
Vous devriez maintenant voir tous les fichiers situés dans destdir :
$ tree -a
.
├── destdir
│ ├── ..d1
│ ├── ..d2
│ ├── ..double
│ ├── file-1
│ ├── file-2
│ ├── .hidden-1
│ ├── .hidden-2
│ ├── ...t1
│ └── ...t2
└── sourcedir
Vous pouvez faire des choses assez cool avec des accolades en bash avec encore plus d'ajouts en 4.x. Consultez bash-hackers pour quelques exemples astucieux.
Vous pourriez également être en mesure de trouver et de grep avec des guillemets arrière pour sélectionner des fichiers pour la commande de déplacement. Passez-les en mv.
C'est à dire. Pour les fichiers cachés
find Foo -maxdepth 1 | egrep '^Foo/[.]' # Output: .hidden
Donc
mv `find Foo -maxdepth 1 | egrep '^Foo/[.]'` Bar # mv Foo/.hidden Bar
Déplace uniquement les fichiers cachés sélectionnés dans Bar
:
mv `find Foo -maxdepth 1 | egrep '^Foo/.'` Bar # mv Foo/.hidden Foo/notHidden Bar
Déplace tous les fichiers de Foo vers Bar depuis le '.' dans la commande egrep agit comme un caractère générique sans les crochets.
Le ^
assure que la correspondance commence au début de la ligne.
Quelques détails sur egrep
la correspondance des modèles peuvent être trouvés ici .
En utilisant maxdepth 1
empêche la recherche d'accéder aux sous-répertoires.
Inspiré de cette réponse :
Sans copier les fichiers ...
rsync -ax --link-dest=../Foo/ Foo/ Bar
Mises en garde:
--link-dest
le chemin doit être absolu ou relatif à DESTINATION (Bar
dans l'exemple)
Vous devez mettre /
après SOURCE (Foo/
dans l'exemple), sinon il copiera le dossier SOURCE au lieu de son contenu.