#bash #path #posix
#bash #путь #posix
Вопрос:
Утилита which
найдет программу по указанному пути, но как насчет произвольного файла данных?
Должно быть, я ищу не тот материал, но я не могу найти никакого способа сделать это с помощью стандартной утилиты, поэтому я подумал о написании небольшого скрипта Bash для этого.
$PATH
Переменная среды разделяется двоеточиями, но попытка установить IFS=':'
, а затем выполнить итерацию по результатам, у меня не работает. Вот что у меня получилось на данный момент:
IFS=':' DIRS=($PATH)
for d in $DIRS; do echo $d; done
На данный момент он выводит только первую запись в моем path, а не все из них.
Мысли? Если уже есть стандартная команда, которая делает это, тогда нет смысла писать скрипт …
Комментарии:
1. Произвольные файлы данных, вероятно, не должны находиться в списках каталогов в
PATH
.
Ответ №1:
Используя это, используя расширения параметров bash и find
:
find ${PATH//:// } -name 'file'
Комментарии:
1. Предположим, что в пути есть каталог, в котором есть пробел. Или файл в каталоге по ПУТИ с пробелом в имени файла.
2. Вы также не расширяете файлы в последней записи ПУТИ.
3. Это решение было бы здорово, если бы я мог использовать
find
таким образом, чтобы выполнялся поиск$PATH
, но замена двоеточий пробелами не сработает4. @GillesQuenot Я поддержал ваше
find
решение, потому что оно мне нравится, но оно не будет работать, когда в каталогах, которые находятся в$PATH
5. Я никогда не использую пробелы, особенно для каталога PATH, и мне тоже нравится мое решение ^^
Ответ №2:
Ошибка не в присваивании, а в том, что не выполняется цикл по массиву.
IFS=: dirs=($PATH)
for dir in "${dirs[@]}"; do
echo "$dir"
done
у меня работает; или более кратко
printf '%sn' "${dirs[@]}"
Как вы обнаружили, just $dirs
возвращает только первый элемент из массива.
Чтобы на самом деле обойти эти каталоги в поисках определенного файла, возможно, попробуйте
desired_file_name=$1 # or whatever
for dir in "${dirs[@]}"; do
test -e "$dir/$desired_file_name" || continue
echo "$0: found $dir/$desired_file_name" >amp;2
done
Другой подход заключается
find "${dirs[@]}" -name "$desired_file_name"
(Вы должны предпочитать нижний регистр для своих личных переменных, поэтому я изменил DIRS
на dirs
. Меньше криков тоже полезно для глаз.)
Комментарии:
1. Ха, похоже, я не проверил то, что написал.
Ответ №3:
Здесь происходит несколько вещей:
-
IFS=':' DIRS=($PATH)
bash развернет переменную перед установкой IFS и DIRS, поэтому к тому времени будет слишком поздно. Вам понадобится что-то сумасшедшее, например
dirs=() while IFS= read -r -d: dir || [ "$dir" ]; do dirs =("$dir"); done <<<"$PATH"
— нет, это было неправильно. Сначала расширяется переменная $PATH, затем устанавливается IFS, затем элемент DIRS разделяется с использованием IFS, поскольку он не заключен в кавычки.
-
for d in $DIRS; do echo $d; done
Чтобы выполнить итерацию по всем элементам массива, вам нужно
for d in "${dirs[@]}" ...
С массивом,
$DIRS
равным${DIRS[0]}
, то есть первой записи. -
Не используйте ALLCAPS varnames. Слишком просто перезаписать важную системную переменную.
-
Заключайте свои переменные в кавычки, если вы не знаете точно, что произойдет, если вы этого не сделаете.
Ответ №4:
Чтобы найти файл с именем $name
на вашем PATH
компьютере, используйте цикл bash:
oldIFS=$IFS
IFS=:
for d in $PATH
do
[ -f "$d/$name" ] amp;amp; echo "Found $d/$name"
done
IFS=$oldIFS
Во многих системах, таких как debian, which
это просто сценарий оболочки, и он использует очень похожий цикл. Взгляните на less /usr/bin/which
.