web-dev-qa-db-fra.com

Comment déplacer des fichiers inconnus vers des répertoires inconnus en fonction du nom du dossier?

J'essaie d'écrire un script qui va rechercher un dossier dans un répertoire et déplacer le contenu du dossier d'un répertoire à partir de son emplacement. Voici ce que j'ai jusqu'à présent:

find ./localFolders -name 'file' -type d -exec mv {}/* .. \;

Je pense que mon problème réside dans le répertoire de destination de ... peut-être que je me trompe?

Toute aide est utile.

* éditer **

pour simplifier ce mal aller dans plus d'infos

Je suis avec une organisation qui tente de passer de MS Exchange à Zimbra. Dans le cadre de notre migration, nous avons trouvé d'excellents utilitaires de transfert de boîtes aux lettres, mais le transfert de fichiers PST au format utilisable de Zimbra s'avère difficile.

J'ai cependant trouvé des solutions pour faire une histoire courte, j'ai été capable de transformer des fichiers pst en un format utilisable, à une exception près -

au lieu de placer le courrier dans ce dossier, un sous-répertoire appelé “mbox” est créé, qui ressemble vraisemblablement au fichier mbox à partir duquel les fichiers .eml sont décomposés. Étant donné que chaque utilisateur est différent et utilise des structures de dossiers différentes de celles des autres utilisateurs, chaque répertoire est inconnu jusqu'à l'exécution du script. De plus, le contenu du dossier mbox est également unique.

Parce que le dossier nommé mbox est la seule constante de ces répertoires que j'essaie d'utiliser find pour localiser ces dossiers, prenez le contenu de ces dossiers et déplacez-les d'un répertoire vers le haut, puis supprimez le dossier nommé mbox. Voici la commande réelle telle qu'elle apparaît dans mon script:

find localFolders -name mbox -type d -exec mv {}/* .. \;

ou dans l'exemple que vous venez de donner:

find localFolders -name mbox -type d -execdir sh -c 'echo mv {}/* ..' \;

J'essaie d'utiliser le * comme caractère générique pour tout sélectionner dans le dossier mbox. Autant que je sache, il est au contraire traité comme faisant partie du répertoire, et non comme un caractère générique.

pensées?

2
Don

Que dis-tu de ça?

find ./localFolders -name 'file' -type d -execdir bash -c 'mv -vnt . -- "$0"/*' {} \; -Prune

Coffre-fort en ce qui concerne les espaces et les symboles amusants dans les noms de fichiers. Prendre plaisir!

1
gniourf_gniourf

Afin de faire ce que vous voulez correctement en utilisant find, vous devez comprendre les concepts suivants:

  1. Le répertoire de travail d'un processus.
  2. La fonction glob de bash (ou d'autres coquilles).

Chaque processus sous Linux a un répertoire de travail faisant partie de son état interne. Vous pouvez l’imaginer comme "l’emplacement" du processus dans le système de fichiers. Le shell est également un processus et dispose également d’un répertoire de travail. Le répertoire de travail du shell est le répertoire (généralement) affiché dans votre invite.

Lorsqu'un processus est créé, il hérite du répertoire de travail de son parent. Si vous démarrez un processus à partir du shell, celui-ci est le parent. Chaque processus peut changer son propre répertoire de travail à volonté. Vous pouvez modifier le répertoire de travail du shell à l’aide de la commande intégrée cd.

Le répertoire de travail est utilisé lorsqu'il s'agit de noms de fichiers relatifs. Les noms de fichiers relatifs sont des noms de fichiers qui ne commencent pas par /. Par exemple, lorsque vous faites cat foo, il recherchera le fichier foo dans le répertoire de travail en cours, mais lorsque vous effectuerez cat /tmp/foo, il recherchera le fichier foo dans /tmp.

Lorsque vous utilisez find -exec, vous devez toujours penser au répertoire de travail. Le répertoire de travail de -exec est le répertoire de travail de find. Le répertoire de travail de find est le répertoire de travail du shell.

Dans ton cas:

find ./localFolders -name 'file' -type d -exec mv {}/* .. \;

Le .. fera référence au répertoire parent du répertoire de travail de mv qui est le répertoire de travail de -exec qui est le répertoire de travail de find qui est le répertoire de travail. du shell au moment où vous avez exécuté la commande. Ce n'est pas ce que tu voulais.

Il existe un -execdir qui ressemble à -exec, mais il commute d'abord le répertoire de travail vers le répertoire dans lequel se trouve l'élément correspondant. -execdir représente un grand pas en avant vers la solution de votre question, mais il existe un autre problème dans votre commande find: le * a.k.a. glob.

Un glob est quelque chose qui ressemble à un joker. Par exemple, foo* correspondra à foobar et foobaz (et foo parce que * correspond également à la chaîne nulle). Jusqu'ici tout va bien. La partie intéressante de globbing est que cela est fait par le shell, pas par la commande exécutée. Lorsque vous exécutez rm foo*, le shell développera d'abord * en foobar et foobaz, puis exécutera rm foobar foobaz. rm ne voit jamais le *.

Que se passe-t-il lorsqu'il n'y a aucun fichier commençant par foo dans le répertoire actuel? Ensuite, le shell (en général) ne développera pas le * et transmettra le * à la commande in extenso. Cela signifie que rm foo* sera exécuté en tant que rm foo*. rm recherchera un fichier nommé foo* et ne le trouvera (probablement) pas, et abandonnera avec une erreur. Si vous vous posez la question suivante: oui, il est possible qu'un nom de fichier contienne *, non, n'essayez pas cela à la maison.

Dans ton cas:

find ./localFolders -name 'file' -type d -exec mv {}/* .. \;

Avant d'exécuter la commande find, le shell tentera d'abord de développer le glob {}/*. Il n'y a pas de fichiers correspondant au modèle {}/* donc le glob sera transmis mot pour mot.

Voyons ce que fait la commande find. Supposons que vous exécutiez la commande find à partir de /home/username/somedir et qu'il existe un répertoire /home/username/somedir/localFolders/foodir/file contenant des fichiers. find commencera la recherche dans /home/username/somedir/localFolders car les paramètres le spécifient, mais le répertoire de travail de find est /home/username/somedir car il a été exécuté à partir de là.

Maintenant, find a trouvé le répertoire /home/username/somedir/localFolders/foodir/file. Avant d'exécuter le -exec, il remplacera le {} par l'élément trouvé. Cela signifie que mv {}/* .. deviendra mv /home/username/somedir/localFolders/foodir/file/* ... mv échouera car il ne trouvera (probablement pas) un fichier nommé *.

Supposons qu'il existe un fichier nommé * puis mv le déplacera vers ... Rappelez-vous que le répertoire de travail est /home/username/somedir. Cela signifie que mv déplacera le fichier vers /home/username/somedir/.. qui est /home/username. Ce n'est pas ce que tu voulais.

Le "correctif" de votre commande find dépend de plusieurs facteurs. Par exemple:

  • Existe-t-il des "fichiers de points" dans le répertoire file? Les fichiers de points sont des fichiers dont le nom commence par un point. Le globule * ne sera généralement pas étendu aux noms de fichiers commençant par un point.
  • Existe-t-il d'autres répertoires dans le répertoire file? find essaiera de récidiver, mais échouera car ils ont été déplacés.
  • Existe-t-il des répertoires nommés file dans le répertoire file? Où doivent aller ces fichiers?
  • Y at-il un million de fichiers dans le répertoire file? Cela risquerait de gâcher le développement de * glob.
  • Existe-t-il des conflits de noms de fichiers avec des fichiers situés hors du répertoire file? Devraient-ils être écrasés?
  • Y a-t-il des espaces dans les noms de fichiers? Cela va tout gâcher.

Pour corriger votre commande find, je vais volontiers ignorer tous ces facteurs.

Voici un correctif utilisant -execdir et sh -c pour retarder le développement de *:

find ./localFolders -name file -type d -execdir sh -c 'mv {}/* ..' \;

Comme le * est entre guillemets, il ne sera pas développé à l’avance. Lorsque -execdir exécute la commande, alors sh -c étendra le * dans le répertoire de travail.

Voici un autre correctif sans sh -c:

find ./localFolders -path "*/file/*" -execdir mv {} .. \;

J'ai utilisé -path pour rechercher tous les éléments sous des répertoires portant le nom file. Les * sont entre guillemets, ils ne seront donc pas développés à l’avance. Cette fois, find se charge de l'interprétation du *. Notez que cela correspond également à quelque chose comme ./localFolders/foodir/file/bardir/file/somefile. Comme je l'ai dit, j'ai heureusement ignoré ce facteur.

Et par souci d’exhaustivité, un autre correctif sans -execdir:

find ./localFolders -name file -type d -exec sh -c 'mv {}/* {}/..' \;
1
lesmana