Napisałem mały skrypt bash, aby sprawdzić, czy katalog ma nazwę anaconda
czy miniconda
w moim użytkowniku $HOME
. Ale nie znajduje miniconda2
katalogu w moim domu.
Jak mogę to naprawić?
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: Jeśli tak [ -d "$HOME"/miniconda2 ]; then
, to znajduje katalog miniconda2, więc myślę, że w tym leży błąd"(ana|mini)conda[0-9]?"
Chcę, aby skrypt był ogólny. Dla mnie jest to miniconda2, ale dla innego użytkownika może to być anaconda2, miniconda3 i tak dalej.
command-line
bash
scripts
Przędzarka
źródło
źródło
Odpowiedzi:
Jest to zaskakująco trudna rzecz do zrobienia.
Zasadniczo
-d
przetestuje tylko jeden argument - nawet jeśli można dopasować nazwy plików za pomocą wyrażeń regularnych.Jednym ze sposobów byłoby odwrócenie problemu i przetestowanie katalogów pod kątem dopasowania wyrażenia regularnego zamiast testowania dopasowania wyrażenia regularnego dla katalogów. Innymi słowy, przeglądaj wszystkie katalogi
$HOME
za pomocą prostego globu powłoki i testuj każdy z wyrażeniem regularnym, przerywając dopasowanie, w końcu sprawdzając, czyBASH_REMATCH
tablica nie jest pusta:Alternatywnym sposobem byłoby użycie rozszerzonego globu powłoki zamiast wyrażenia regularnego i przechwytywanie dowolnych dopasowań globów w tablicy. Następnie sprawdź, czy tablica nie jest pusta:
Końcowe
/
zapewnia dopasowanie tylko katalogów;nullglob
zabezpiecza powłokę przed powrotem niedopasowanej ciąg w przypadku zerowej meczów.Aby ustawić rekurencję, ustaw
globstar
opcję powłoki (shopt -s globstar
), a następnie odpowiednio:(wersja regularna):
for d in "$HOME"/**/; do
(rozszerzona wersja globalna):
dirs=( "$HOME"/**/@(ana|mini)conda?([0-9])/ )
źródło
?([0-9])
zamiast@(|[0-9])
-?(...)
dopasowuje zero lub jeden, tak samo jak?
kwantyfikator wyrażenia regularnego .~/{ana,mini}conda{0..9}*/
mini
lubanaconda
jest zainstalowana w$HOME/sub-directories
? Na przykład$HOME/sub-dir1/sub-dir2/miniconda2
globstar
Rzeczywiście, jak już wspomniano, jest to trudne. Moje podejście jest następujące:
find
i jego wyrażenia regularne do znajdowania danych katalogów.find
wypisujex
dla każdego znalezionego katalogux
es w ciąguA zatem:
Wyjaśnienie:
find $HOME -maxdepth 1
znajduje wszystko poniżej,$HOME
ale ogranicza wyszukiwanie do jednego poziomu (to znaczy: nie powraca do podkatalogów).-type d
ogranicza wyszukiwanie tylko dod
irectories-regextype egrep
mówi, zfind
jakim rodzajem wyrażenia regularnego mamy do czynienia. Jest to potrzebne, ponieważ rzeczy takie jak[0-9]?
i(…|…)
są nieco wyjątkowe ifind
domyślnie ich nie rozpoznają.-regex "$HOME/(ana|mini)conda[0-9]?"
jest właściwym wyrażeniem regularnym, którego chcemy szukać-printf 'x'
po prostu drukujex
dla każdej rzeczy, która spełnia poprzednie warunki.źródło
-bash: -regex: command not found found one of the directories
printf
pojawia się błąd na przykład, kiedy uruchamiam skrypt, działa on dobrze, ale nie znajduje polecenia printf, gdy nie ma dopasowania, ale myślę, że dzieje się tak, ponieważ może nie być nic do wydrukowania ?.-bash: -printf: command not found no match.
-printf
nie jest poleceniem, ale argumentem nafind
. To właśnie robi odwrotny ukośnik na końcu poprzedniej linii.-quit
po wydrukowaniu znalezionej ścieżki, chyba że chcesz nadal wykrywać dwuznaczności.x
zamiast tego użyć :foundDir=$(find $HOME -maxdepth 1 -type d -regextype egrep -regex "$HOME/(ana|mini)conda[0-9]?" -print -quit); echo "found $foundDir"
Możesz przewinąć listę nazw katalogów, które chcesz przetestować, i wykonać na niej działania, jeśli jedna z nich istnieje:
To rozwiązanie oczywiście nie pozwala na pełną moc wyrażania regularnego, ale globowanie powłoki i rozwijanie nawiasów jest równe przynajmniej w pokazanym przypadku. Pętla kończy się, gdy tylko istnieje jeden katalog i resetuje poprzednio ustawioną zmienną
a
. W kolejnymecho
wierszu rozszerzenie parametru${a+not }
rozwija się do zera, jeślia
jest ustawione (= nie znaleziono katalogu ) i „nie”.źródło
Możliwym obejściem jest osobne przeszukiwanie minikondy i anakondy, jak pokazano poniżej
Ale jeśli ktoś ma sugestie, chciałbym wiedzieć, dlaczego nie możemy przekazać wyrażenia regularnego podczas wyszukiwania katalogów.
źródło
shopt -s nullglob; dirs=( "$HOME"/miniconda* "$HOME"/anaconda* ); if (( ${#dirs[@]} > 0 )); then ...
] || [
z-o
nim przynajmniej nie powinny pęknąć, jeśli znajdują się zarówno katalogi jak oba globs katalogowych są spojrzał w tym samym teście.