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?
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!
Afin de faire ce que vous voulez correctement en utilisant find
, vous devez comprendre les concepts suivants:
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:
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.file
? find
essaiera de récidiver, mais échouera car ils ont été déplacés.file
dans le répertoire file
? Où doivent aller ces fichiers?file
? Cela risquerait de gâcher le développement de *
glob.file
? Devraient-ils être écrasés?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 {}/* {}/..' \;