Comment déplacez-vous tous les fichiers (y compris les fichiers cachés) d'un répertoire à un autre?

135

Comment déplacer tous les fichiers d'un répertoire (y compris ceux qui sont 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 puis-je 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 vous-même.

mkdir Foo
mkdir Bar
touch Foo/.hidden
touch Foo/notHidden
mv Foo/* Bar/
Cory Klein
la source
Bah, je savais que j'aurais dû rafraîchir les réponses avant de taper les miennes. Lien très utile.
Steven D
Malheureusement, cette question s’est terminée ici parce que j’ai dit à SO qu’elle devait être déplacée ici ou bien à SU, alors bien sûr qu’elle s’est déplacée ici alors qu’il y avait déjà un doublon sur SU: :)
Michael Mrozek
Personnellement, je pense que les * nix questions et réponses spécifiques devraient être hors sujet sur SU. Avec les règles actuelles, nous nous retrouvons avec des tonnes de collisions de contenu entre les deux, comme dans le cas de cette question.
Cory Klein

Réponses:

154

Zsh

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.)

Frapper

shopt -s dotglob nullglob
mv Foo/* Bar/

Ksh93

Si vous savez que le répertoire n'est pas vide:

FIGNORE='.?(.)'
mv Foo/* Bar/

Standard (POSIX) sh

for x in Foo/* Foo/.[!.]* Foo/..?*; do
  if [ -e "$x" ]; then mv -- "$x" Bar/; fi
done

Si vous êtes prêt à laisser la mvcommande renvoyer un statut d'erreur même si elle a réussi, c'est beaucoup plus simple:

mv Foo/* Foo/.[!.]* Foo/..?* Bar/

GNU find et GNU mv

find Foo/ -mindepth 1 -maxdepth 1 -exec mv -t Bar/ -- {} +

Recherche standard

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.

Frapper

Définir l' dotgloboption .

$ echo *
none zero
$ shopt -s dotglob
$ echo *
..two .one none zero

Il existe également la GLOBIGNOREvariable plus flexible , que vous pouvez définir comme une liste de modèles de caractères génériques séparés par des points-virgules à ignorer. Si non défini (paramètre par défaut), le shell se comporte comme si la valeur était vide si dotglobest défini et comme si la valeur l'é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, à moins que .le modèle ne corresponde explicitement au modèle.

$ GLOBIGNORE='n*'
$ echo *
..two .one zero
$ echo .*
..two .one
$ unset GLOBIGNORE
$ echo .*
. .. ..two .one
$ GLOBIGNORE=.:..
$ echo .*
..two .one

Ksh93

Définissez la FIGNOREvariable . Si non défini (paramètre par défaut), le shell se comporte comme si la valeur était .*. Pour ignorer .et .., ils doivent être explicitement mis en correspondance (le manuel de ksh 93s + 2008-01-31 indique cela .et ..est toujours ignoré, 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 modèle en les faisant correspondre explicitement.

$ unset FIGNORE
$ echo @(*|.[^.]*|..?*)
..two .one none zero

Pour que l'extension soit sortie vide si le répertoire est vide, utilisez l' Noption de correspondance de modèle: ~(N)@(*|.[^.]*|..?*)ou ~(N:*|.[^.]*|..?*).

Zsh

Définir l' dot_globoption .

% echo *
none zero
% setopt dot_glob
% echo *
..two .one none zero

.et ..ne sont jamais appariés, même si le motif correspond .explicitement au premier .

% echo .*
..two .one

Vous pouvez inclure des fichiers de points dans un modèle spécifique avec le D qualificatif glob .

% echo *(D)
..two .one none zero

Ajouter le Nqualificatif de glob pour faire l'expansion sortir vide dans un répertoire vide: *(DN).


Remarque: vous pouvez obtenir des résultats d'extension noms de fichiers dans des ordres différents (par exemple, nonesuivi de .onesuivi ..two) en fonction de vos paramètres des LC_COLLATE, LC_ALLet des LANGvariables.

Gilles
la source
1
Pourquoi nullglob? Il serait plus logique d'abandonner la mvcommande (comme fish, csh / tcsh, zsh (sans (N)) do ou bash avec failglob) plutôt que d'exécuter une mv /Bar/commande sans grand sens.
Stéphane Chazelas
1
Je dirais que votre description de GLOBIGNORE est inexacte et trompeuse. Réglage GLOBIGNORE à une valeur non vide se fait sur dotglob et que .et ..ne sont jamais égalé (comme dans d' autres coquilles sensibles comme zsh, poissons, pdksh et ses dérivés) , même si vous tournez dotglob dégagez après. ( GLOBIGNORE=:; shopt -u dotglob; echo .*ne sortira pas .et ..). définir GLOBIGNORE sur .:..ou .ou :avoir le même effet.
Stéphane Chazelas
ksh93toujours ignorer .et ..semble avoir été cassé entre ksh93k+(où cela a fonctionné) et ksh93m(où cela ne fonctionne plus). Notez que c’est mauvais en qui ksh93va prendre la valeur de FIGNORE de l’environnement, donc un FIGNORE='!(..)'env var, par exemple, peut créer des dégâts.
Stéphane Chazelas
24
#!/bin/bash

shopt -s dotglob
mv Foo/* Bar/

De man bash

dotglob Si défini, bash inclut les noms de fichiers commençant par un '.' dans les résultats de l'expansion du chemin d'accès.

SiegeX
la source
Avec l'avertissement que cette commande retourne un code d'erreur si le répertoire était vide (même si la commande a réellement fonctionné comme prévu).
Gilles
1
@ Gilles, l'erreur sera alors de se mvplaindre que ce fichier appelé Foo/*n'existe pas. Fait intéressant, si Fooest consultable, mais illisible, et qu’un fichier y est appelé *, vous n’obtiendrez aucune erreur, ce fichier sera déplacé, mais pas les autres dans le répertoire. basha une failgloboption de sorte qu'il se comporte plus comme zsh, fishou csh/ tcshet annuler la commande avec une erreur lorsqu'un glob ne peut pas être élargi au lieu de ce comportement faux de laisser l'as-est glob.
Stéphane Chazelas
8

Un moyen simple de le faire bashest

mv {Foo/*,Foo/.*} Bar/

Mais cela va aussi déplacer les répertoires.

Si vous souhaitez déplacer tous les fichiers, y compris les fichiers 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;

Boris Mois
la source
4

Une façon est d'utiliser find:

find Foo/ -type f -exec mv -t Bar/ {} \+

La -type flimite la commande find à la recherche de fichiers. Vous devez enquêter sur la -type, -maxdepth, et les -mindepthoptions de findpour personnaliser votre commande pour compte pour les sous - répertoires. Find a une page de manuel longue mais très utile .

Steven D
la source
3
Cela ne fait que déplacer les fichiers normaux Foo/, pas les sous-répertoires et autres fichiers.
Gilles
2

Essayez la commande de copie cp:

$ cp -r myfolder/* destinationfolder

cp -r signifie copier récursif, ainsi tous les dossiers et fichiers seront copiés.

Vous pouvez utiliser la commande rmremove pour supprimer un dossier:

$ rm -r myfolder

Voir plus: déplace tous les fichiers d'un répertoire à un autre .

Ucefkh
la source
2
Pas le meilleur lorsque vous déplacez beaucoup de gros fichiers, mais je suppose que cela fonctionnerait.
Cory Klein
Peut-être si vous utilisez un point au lieu de l'étoile?
Vincent
1

Rsync est une autre option:

rsync -axvP --remove-source-files sourcedirectory/ targetdirectory

Cela fonctionne car dans rsync la fin de la barre oblique est importante, elle sourcedirectory/fait référence au contenu du répertoire, alors qu'elle sourcedirectoryferait référence au répertoire lui-même.

L'inconvénient de cette méthode est que rsync ne nettoie que les fichiers après le déplacement, pas le répertoire. Il ne reste donc qu’un arbre sourcedirectory. 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, cela peut s'avérer extrêmement utile pour les opérations de copie.

Grumbel
la source
1

Réponse pour bash / poisson

Voici un moyen de le faire en utilisant des caractères génériques:

.[!.]* ..?*correspondra à tous les fichiers cachés sauf .et..

.[!.]* ..?* *correspondra à tous les fichiers (cachés ou non) sauf .et..

Et pour répondre à l'exemple particulier de cette question, vous avez besoin cd foo && mv .[!.]* ..?* * ../bar

Explication

.[!.]*correspond aux noms de fichiers commençant par un point, suivi de tout caractère sauf le point éventuellement suivi d'une chaîne. Ceci est assez proche mais il manque des fichiers commençant par deux points comme ..foo. Pour inclure de tels fichiers, nous ajoutons ceux ..?*qui correspondent aux noms de fichiers commençant par deux points, suivis de tout caractère, éventuellement suivis de toute chaîne.

Tester

Vous pouvez tester ces caractères génériques avec les commandes ci-dessous. Je les ai essayées avec succès sous le poisson et bash. 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
Ndemou
la source
0

Vous pourriez également être en mesure de trouver et de grep avec des citations arrières pour sélectionner les fichiers pour la commande de déplacement. Pass ceux en mv.

Ie pour les fichiers cachés

find Foo -maxdepth 1 | egrep '^Foo/[.]' # Output: .hidden

Alors

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 à Bar depuis le '.' dans la commande egrep agit comme un caractère générique sans les crochets.

Le ^personnage veille à ce que la correspondance commence au début de la ligne.

Vous trouverez quelques détails sur egrepla correspondance des motifs ici .

Utilisation des maxdepth 1arrêts dans les sous-répertoires.

utilisateur3192145
la source
0

Inspiré de cette réponse :

Sans copier les fichiers ...

rsync -ax --link-dest=../Foo/ Foo/ Bar

Mises en garde:

  • --link-destchemin doit être absolu ou relatif à DESTINATION ( Bar dans l'exemple)

  • Vous devez mettre /après SOURCE ( Foo/dans l'exemple), sinon le dossier SOURCE sera copié au lieu de son contenu.

palindrom
la source
0

Je trouve que cela fonctionne bien pour bash et qu'il n'y a pas besoin de changer les options du shell

mv sourcedir/{*,.[^.]*} destdir/

MODIFIER:

Donc, comme G-man l’a dit, ma réponse initiale n’est pas conforme à posix et est à peu près identique à la réponse de ndemou ci-dessus avec une modification, qui consiste à utiliser le développement par accolade pour créer des listes de chaînes sur lesquelles une action est ensuite effectuée. Cela signifie simplement que vous n'avez pas besoin d' cdentrer dans le répertoire source. Ce n'est pas vraiment un gros changement, mais c'est différent.

exemple: disons que vous avez déjà la disposition suivante.

 $ tree -a
.
├── destdir
└── sourcedir
    ├── ..d1
    ├── ..d2
    ├── ..double
    ├── file-1
    ├── file-2
    ├── .hidden-1
    ├── .hidden-2
    ├── ...t1
    └── ...t2

La question initiale ne mentionnait que les fichiers cachés avec une seule période, mais supposons qu'il y en ait avec deux ou plusieurs points au début du nom. Vous pouvez simplement ajouter une expression supplémentaire dans les accolades. Nous pouvons alors exécuter

mv sourcedir/{*,.[!.]*,..?*} destdir/

Cela devient étendu à ce qui 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 le répertoire destdir :

 $ tree -a
.
├── destdir
   ├── ..d1
   ├── ..d2
   ├── ..double
   ├── file-1
   ├── file-2
   ├── .hidden-1
   ├── .hidden-2
   ├── ...t1
   └── ...t2
└── sourcedir

Vous pouvez faire des choses vraiment cool avec des accolades en bash avec encore plus d'ajouts en 4.x. Découvrez bash-hackers pour quelques exemples intéressants.

cmndr sp0ck
la source
1
En gros, cela duplique la réponse de ndemou sauf que vous avez ajouté des accolades (sans les expliquer). Mais (1) votre réponse ne correspond pas aux fichiers dont le nom commence par .., et (2) pour être compatible POSIX , vous devez utiliser à la !place de ^; c'est à dire  {*,.[!.]*}.
G-Man
@ G-Man, désolé pour ça. Donc, vous avez raison et mon mal de ne pas voir la réponse de ndemou. Ils sont à peu près la même chose. 1. merci de signaler que ma version n’est pas conforme à posix. 2. J'utilise l'extension d'accolade pour créer des listes de chaînes que le shell utilisera ensuite pour effectuer une action. Cela signifie également que je n'ai pas besoin d' cdentrer dans le répertoire source pour agir sur les fichiers ou écrire les mêmes chemins d'accès aux fichiers à plusieurs reprises pour exprimer les chemins d'accès à tous les fichiers. Je mettrai à jour l'exemple prochainement pour donner à tous les lecteurs une meilleure idée de ce dont je parle.
CMND Sp0ck
0

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 ne seront pas réellement déplacés).

mv /sourceDir/* /destinationDir 2> /dev/null
mv /sourceDir/.* /destinationDir 2> /dev/null

Remarques: S'il n'y a pas de contenu visible, la première commande produira un message d'erreur. La deuxième commande produira toujours une erreur en disant qu'il ne peut pas bouger .et ... En tant que tel, il suffit de canaliser les erreurs /dev/null(comme indiqué).

Si vous avez besoin de cela comme une ligne, combinez-les simplement avec un point-virgule:

mv /sourceDir/* /destinationDir 2> /dev/null; mv /sourceDir/.* /destinationDir 2> /dev/null
BuvinJ
la source