Я написал небольшой скрипт bash, чтобы найти каталог с именем anaconda
или miniconda
у моего пользователя $HOME
. Но он не находит miniconda2
каталог в моем доме.
Как я мог это исправить?
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: если у меня есть [ -d "$HOME"/miniconda2 ]; then
, то он находит каталог miniconda2, поэтому я думаю, что ошибка лежит в части"(ana|mini)conda[0-9]?"
Я хочу, чтобы сценарий был общим. Для меня это miniconda2, но для другого пользователя это может быть anaconda2, miniconda3 и так далее.
command-line
bash
scripts
Дженни
источник
источник
Ответы:
Это удивительно сложно сделать красиво.
По сути,
-d
будет проверять только один аргумент - даже если вы можете сопоставить имена файлов с помощью регулярного выражения.Одним из способов было бы перевернуть проблему и проверить каталоги на соответствие регулярному выражению вместо проверки соответствия регулярного выражения на наличие каталогов. Другими словами, переберите все каталоги,
$HOME
используя простой глобус оболочки, и проверьте каждый на соответствие вашему регулярному выражению, разбив совпадение и, наконец,BASH_REMATCH
проверив, не является ли массив непустым:Альтернативным способом было бы использовать расширенный глобус оболочки вместо регулярного выражения и записывать любые совпадения глобуса в массиве. Затем проверьте, не является ли массив непустым:
Трейлинг
/
гарантирует, что сопоставляются только каталоги;nullglob
предотвращает скорлупу от возвращения непревзойденной строки в случае нулевых матчей.Чтобы сделать либо рекурсивный, установите параметр
globstar
оболочки (shopt -s globstar
), а затем соответственно: -(регулярное выражение):
for d in "$HOME"/**/; do
(расширенная глобальная версия):
dirs=( "$HOME"/**/@(ana|mini)conda?([0-9])/ )
источник
?([0-9])
вместо@(|[0-9])
-?(...)
соответствует нулю или единице, так же, как?
квантор регулярного выражения.~/{ana,mini}conda{0..9}*/
mini
иanaconda
установлен в$HOME/sub-directories
? Например$HOME/sub-dir1/sub-dir2/miniconda2
globstar
Действительно, как уже упоминалось, это сложно. Мой подход заключается в следующем:
find
и его возможности регулярных выражений , чтобы найти соответствующие каталоги.find
распечатаетx
для каждого найденного каталогаx
ES в строкеТаким образом:
Объяснение:
find $HOME -maxdepth 1
находит все ниже,$HOME
но ограничивает поиск до одного уровня (то есть: он не переходит в подкаталоги).-type d
ограничивает поиск толькоd
каталогами-regextype egrep
говорит, сfind
каким типом регулярных выражений мы имеем дело. Это необходимо, потому что такие вещи как[0-9]?
и(…|…)
являются чем-то особенным иfind
не распознают их по умолчанию.-regex "$HOME/(ana|mini)conda[0-9]?"
фактическое регулярное выражение, которое мы хотим найти-printf 'x'
просто печатаетx
для каждой вещи, которая удовлетворяет предыдущим условиям.источник
-bash: -regex: command not found found one of the directories
printf
Например, когда я запускаю скрипт, он работает нормально, но не находит команду printf, когда нет совпадения, но я думаю, что это потому, что нечего печатать, может быть ?.-bash: -printf: command not found no match.
-printf
это не команда, а аргументfind
. Это то, что делает обратная косая черта в конце предыдущей строки.-quit
после печати найденного пути, если вы не хотите продолжать обнаруживать неоднозначность.x
вместо этого:foundDir=$(find $HOME -maxdepth 1 -type d -regextype egrep -regex "$HOME/(ana|mini)conda[0-9]?" -print -quit); echo "found $foundDir"
Вы можете перебрать список имен каталогов, которые вы хотите протестировать, и действовать по нему, если одно из них существует:
Это решение, очевидно, не учитывает всю мощь регулярных выражений, но сглаживание оболочки и расширение фигурных скобок равны, по крайней мере, в показанном вами случае. Цикл завершается, как только существует один каталог, и сбрасывает ранее установленную переменную
a
. В следующейecho
строке раскрытие параметра${a+not }
расширяется до нуля, еслиa
установлено (= dir не найден) и «нет» в других случаях.источник
Возможный обходной путь - поиск миниконды и анаконды отдельно, как показано ниже
Но если у кого-то есть предложения, я хотел бы знать, почему мы не можем передать регулярное выражение при поиске каталогов.
источник
shopt -s nullglob; dirs=( "$HOME"/miniconda* "$HOME"/anaconda* ); if (( ${#dirs[@]} > 0 )); then ...
] || [
с-o
ним , по крайней мере не должны сломаться , если оба каталога находятся в обоих шариков каталог ищутся в том же тесте.