Как найти файл на $ PATH в Bash? - PullRequest
0 голосов
/ 27 марта 2019

Утилита which найдет программу по пути, но как насчет произвольного файла данных?

Я, должно быть, ищу неправильные вещи, но я не могу найти способ сделать это с помощью стандартной утилиты, поэтому я подумал о написании небольшого скрипта Bash для этого.

Переменная окружения $PATH отделена двоеточиями, но попытка установить IFS=':' и последующий просмотр результатов не работает для меня. Вот что у меня так далеко:

IFS=':' DIRS=($PATH)
for d in $DIRS; do echo $d; done

На данный момент он выводит только первую запись на моем пути, а не все.

Мысли? Если уже есть стандартная команда, которая делает это, то нет смысла писать скрипт ...

Ответы [ 4 ]

3 голосов
/ 27 марта 2019

Здесь происходит несколько вещей:

  1. IFS=':' DIRS=($PATH)

    bash расширит переменную до настройки IFS иDIRS, так что уже слишком поздно.Вам понадобится что-то сумасшедшее, как

    dirs=()
    while IFS= read -r -d: dir || [ "$dir" ]; do dirs+=("$dir"); done <<<"$PATH"
    

- нет, это было неправильно.Сначала раскрывается переменная $ PATH, затем устанавливается IFS, а затем элемент DIRS разделяется с использованием IFS, потому что он не заключен в кавычки.

  1. for d in $DIRS; do echo $d; done

    Для итерациивсе элементы массива, вам нужно

    for d in "${dirs[@]}" ...
    

    С массивом $DIRS равен ${DIRS[0]}, то есть первая запись.

  2. Донне использовать ALLCAPS varnames.Переписать критически важную системную переменную слишком просто.

  3. Заключите в кавычки ваши переменные , если вы не знаете точно , что произойдет, если вы этого не сделаете.

2 голосов
/ 27 марта 2019

Ошибка не в присваивании, а в цикле по массиву.

IFS=: dirs=($PATH)
for dir in "${dirs[@]}"; do
    echo "$dir"
done

работает на меня; или более кратко

printf '%s\n' "${dirs[@]}"

Как вы обнаружили, $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" >&2
done

Другой подход

find "${dirs[@]}" -name "$desired_file_name"

(Вы должны предпочесть строчные буквы для своих личных переменных, поэтому я изменил DIRS на dirs. Меньше криков тоже хорошо для глаз.)

2 голосов
/ 27 марта 2019

Чтобы найти файл с именем $name на вашем PATH с помощью цикла bash:

oldIFS=$IFS
IFS=:
for d in $PATH
do
    [ -f "$d/$name" ] && echo "Found $d/$name"
done
IFS=$oldIFS

Во многих системах, таких как debian, which - это просто сценарий оболочки, и он использует очень похожий цикл. Посмотрите на less /usr/bin/which.

2 голосов
/ 27 марта 2019

Используя это, используя bash расширения параметров anfd find:

find ${PATH//:/\/ } -name 'file'
...