J'ai écrit un petit script bash pour trouver un répertoire nommé anaconda
ou miniconda
dans mon utilisateur $HOME
. Mais il ne trouve pas le miniconda2
répertoire chez moi.
Comment pourrais-je résoudre ce problème?
if [ -d "$HOME"/"(ana|mini)conda[0-9]?" ]; then
echo "miniconda directory is found in your $HOME"
else
echo "anaconda/miniconda is not found in your $HOME"
fi
PS: Si je l'ai [ -d "$HOME"/miniconda2 ]; then
, il trouve le répertoire miniconda2, donc je pense que l'erreur réside dans la partie"(ana|mini)conda[0-9]?"
Je veux que le script soit général. Pour moi, c'est miniconda2 mais pour un autre utilisateur, il peut s'agir d'anaconda2, miniconda3 et ainsi de suite.
command-line
bash
scripts
Jenny
la source
la source
Réponses:
C'est une chose étonnamment délicate à faire correctement.
Fondamentalement,
-d
ne testera qu'un seul argument - même si vous pouvez faire correspondre les noms de fichiers en utilisant une expression régulière.Une façon serait de retourner le problème et de tester les répertoires pour une correspondance regex au lieu de tester la correspondance regex pour les répertoires. En d'autres termes, parcourez tous les répertoires en
$HOME
utilisant un simple glob de shell, et testez chacun contre votre regex, rompant une correspondance, testant enfin si leBASH_REMATCH
tableau n'est pas vide:Une autre façon serait d'utiliser un glob shell étendu à la place de l'expression régulière, et de capturer toutes les correspondances glob dans un tableau. Testez ensuite si le tableau n'est pas vide:
La fin
/
garantit que seuls les répertoires correspondent; lenullglob
empêche le shell de renvoyer la chaîne sans correspondance dans le cas de correspondances nulles.Pour rendre l'un ou l'autre récursif, définissez l'
globstar
option shell (shopt -s globstar
), puis respectivement: -(version regex):
for d in "$HOME"/**/; do
(version glob étendue):
dirs=( "$HOME"/**/@(ana|mini)conda?([0-9])/ )
la source
?([0-9])
à la place de@(|[0-9])
-?(...)
correspond à zéro ou à un, identique au?
quantificateur d' expression régulière.~/{ana,mini}conda{0..9}*/
mini
ouanaconda
est installé dans$HOME/sub-directories
? Par exemple$HOME/sub-dir1/sub-dir2/miniconda2
globstar
En effet, comme déjà mentionné, c'est délicat. Mon approche est la suivante:
find
et ses capacités d' expression régulière pour trouver les répertoires en question.find
imprimer unx
pour chaque répertoire trouvéx
es dans une chaîneDonc:
Explication:
find $HOME -maxdepth 1
trouve tout ci-dessous$HOME
mais restreint la recherche à un niveau (c'est-à-dire: il ne recuit pas dans les sous-répertoires).-type d
restreint la recherche aux seulsd
répertoires-regextype egrep
indiquefind
quel type d' expression régulière nous traitons. Ceci est nécessaire car des choses comme[0-9]?
et(…|…)
sont quelque peu spéciales etfind
ne les reconnaissent pas par défaut.-regex "$HOME/(ana|mini)conda[0-9]?"
est l' expression régulière réelle que nous voulons rechercher-printf 'x'
imprime juste unx
pour chaque chose qui satisfait aux conditions précédentes.la source
-bash: -regex: command not found found one of the directories
printf
Par exemple lorsque j'exécute le script, il s'exécute correctement mais il ne trouve pas la commande printf lorsqu'il n'y a pas de correspondance mais je pense que c'est parce qu'il n'y a rien à imprimer peut-être?.-bash: -printf: command not found no match.
-printf
n'est pas une commande mais un argument pourfind
. C'est ce que fait la barre oblique inversée à la fin de la ligne précédente.-quit
après avoir imprimé le chemin trouvé, sauf si vous voulez continuer à détecter l'ambiguïté.x
place:foundDir=$(find $HOME -maxdepth 1 -type d -regextype egrep -regex "$HOME/(ana|mini)conda[0-9]?" -print -quit); echo "found $foundDir"
Vous pouvez parcourir une liste de noms de répertoires que vous souhaitez tester et agir dessus si l'un d'eux existe:
Cette solution ne permet évidemment pas la pleine puissance des regex, mais l'expansion de la coque et de l'accolade est au moins égale dans le cas que vous avez montré. La boucle se ferme dès qu'un répertoire existe et désactive la variable précédemment définie
a
. Dans laecho
ligne suivante , l' expansion des paramètres se${a+not }
développe à rien sia
est définie (= aucun répertoire trouvé) et «pas» autrement.la source
La solution possible consiste à rechercher séparément miniconda et anaconda comme indiqué ci-dessous
Mais si quelqu'un a des suggestions, j'aimerais savoir pourquoi nous ne pouvons pas passer une expression régulière lors de la recherche de répertoires.
la source
shopt -s nullglob; dirs=( "$HOME"/miniconda* "$HOME"/anaconda* ); if (( ${#dirs[@]} > 0 )); then ...
] || [
par-o
au moins ne devrait pas casser si les deux répertoires sont trouvés car les deux globes de répertoire sont recherchés dans le même test.