выполните команду в $PATH, соответствующем подстановочному знаку

Можно получить свободный экземпляр на Amazon EC2 в течение года. Просто зарегистрируйте и создайте t1.micro экземпляр, который довольно способен к выполнению достойного небольшого веб-сайта.

7
23.02.2015, 01:18
5 ответов

Вот более простая альтернатива:

$(compgen -c libreoffice)

предполагает, что Bash и предполагает, что есть только один LibreOffice * .

Это эмулирует то, что завершение вкладок Bash будет делать, если вы набрали вкладку LibreOffice .

Если вы сознательно пытаетесь исключить LibreOffice без номера версии, и хотите обрабатывать существование нескольких версий, попробуйте:

run_libreoffice() {
    compgen -c libreoffice |
        while read -r exe; do
            case "$exe" in libreoffice?.?)
                "$exe" "$@"
                return
                ;;
            esac
        done
}
run_libreoffice "$@"

Оператор Case делает его совпадение LibreOffice?.? , и мы циклируем по результатам, только бегу только первым.

1
27.01.2020, 20:18

Установите : : : : : , чтобы разделить значение пути на двоеточиях. Если ваш Найти , имеет --Кайт ----Кактеп и -MaxDepth Primary (например, FreeBSD, OSX, GNU), вы знаете, что команда будет существовать, и вы не T Ухаживать за кодом возврата команды, вы можете использовать этот одноклассник:

pattern='libreoffice?.?'
IFS=:; find $PATH -maxdepth 1 -type f -name "$pattern" -exec {} \; -quit; unset IFS

Это не обеспечивает простого способа сообщить, была ли была найдена команда. Кроме того, быть более надежным, отключить глобуску в случае, если значение PATH содержит подстановочные знаки. Кроме того, можно иметь пустой компонент в пути , чтобы означать текущий каталог (но мой совет должен использовать . вместо). Код ниже заботится обо всех этих осложнениях.

pattern='libreoffice?.?'
case $PATH in
  :*) directories=.$PATH;;
  *::*) directories=${PATH%%::*}:.:${PATH#*::};;
  *:) directories=$PATH.;;
  *) directories=$PATH;;
esac
set -f; IFS=:
cmd=
for d in $directories; do
  set +f
  for x in "$d"/$pattern; do
    if [ -x "$x" ] && ! [ -d "$x" ]; then
      cmd=$x
      break
    fi
  done
  if [ -n "$cmd" ]; then break; fi
done
set +f; unset IFS
if [ -z "$cmd" ]; then
  echo 1>&2 "$pattern: not found in PATH"
  exit 127
else
  exec "$cmd"
fi

Если вы будете использовать ZSH (в отличие от простого SH, Bash, KSH, ...), это намного проще сделать надежное решение.

pattern='libreoffice?.?'
matches=($^path/$~pattern(N.*[1]))
if ((!#matches)); then
  $matches[1]
else
  echo 1>&2 "$pattern: not found in PATH"
  exit 127
fi
3
27.01.2020, 20:18

Вы можете использовать команду «найти» следующим образом

find ./ -name "libreoffice?.?"
0
27.01.2020, 20:18

с ZSH :

$commands[(i)libreoffice?.?]

в ZSH , $ Команды - это специальный ассоциативный массив, клавиши которых являются названиями команд и значение их пути.

I выше представляет собой флаг подделок , который говорит ZSH , чтобы соответствовать шаблону на клавишах массива и вернуть первую подходящую клавишу.

Элементы ассоциативного массива не в каком-либо конкретном порядке, хотя, поэтому сначала соответствующий ключ не обязательно будет первым, что происходит в $ PATH . Если вы хотите LibreOffice с наибольшим числом версии, вы можете сделать:

${${(nO)${commands[(I)libreoffice?.?]}}[1]}

Флаг I Flags расширяется до всех соответствующих клавиш. Мы используем N (численное сортировка), а o (обратный порядок) флаги расширения параметров , чтобы сортировать этот список от наибольшего до наименьшего номера версии, а затем [1] Чтобы выбрать первый.

См. Также:

whence -m 'libreoffice?.?'

Чтобы найти пути соответствующих команд.

2
27.01.2020, 20:18

POSIX: при поиске $ PATH исполняемого файла команды следует использовать команду :

  • команду -v
    • Записать строка для стандартного вывода, которая указывает путь или команду, которая будет использоваться оболочкой в ​​текущей среде выполнения оболочки (см. Среда выполнения оболочки , чтобы вызвать имя_команды , но не вызывать имя_команды .
    • ... В противном случае вывод не должен записываться, и статус выхода должен отражать, что имя не было найдено.

Если вызывается без переключателя, команда вызовет имя_команды , но вам все равно нужен полностью разрешенный путь для полного разрешения глобуса оболочки .

Итак, чтобы сделать это, вы должны проверить глобус для каждого элемента : , разделенного двоеточием, в $ PATH в порядке, как spec'd :

  • PATH
    • Эта переменная должна представлять последовательность префиксов пути, что весело При поиске исполняемого файла, известного только под именем , имя файла , применяются специальные средства и утилиты. Префиксы разделяются двоеточием : . Когда к этому имени файла применяется префикс ненулевой длины, между префиксом и именем файла должна быть вставлена ​​косая черта. Префикс нулевой длины - это унаследованная функция , которая указывает текущий рабочий каталог. Он отображается как два соседних двоеточия :: , как начальное двоеточие перед остальной частью списка или как конечное двоеточие после остальной части списка. Строго соответствующее приложение должно использовать фактическое имя пути (например, . ) для представления текущего рабочего каталога в PATH . Список должен просматриваться от начала до конца, применяя имя_файла к каждому префиксу, пока не будет найден исполняемый файл с указанным именем и соответствующими разрешениями на выполнение. Если искомый путь содержит косую черту, поиск по префиксам пути выполняться не будет. Если путь начинается с косой черты, указанный путь разрешается (см. Разрешение пути ) . Если ПУТЬ не задан или установлен в ноль, поиск пути определяется реализацией .

Вы можете разделить $ PATH на поле для каждого компонента $ PATH на $ IFS , но вы можете сделать только это безопасно, если вы также установили -f расширение имени файла как отключенное, пока вы это делаете, в случае, если компонент в $ PATH содержит любой из [? * символов , потому что генерация имени файла (читай: подстановка) происходит после разделения полей в порядке расширения оболочки.

Таким образом, в общем, единственный действительно надежный способ сделать это POSIXly - сначала развернуть список полей на $ IFS , когда генерация имени файла отключена, и каким-то образом сохранить результат этого массива, а затем еще раз включите создание имени файла и отключите разделение полей (чтобы вы могли хранить и расширять свой шаблон глобуса без кавычек в переменной без какой-либо опасности того, что на него повлияет $ IFS first) , и обрабатываем каждый результат по очереди.

К счастью, это не так уж и сложно:

g='libreoffice?.?'
(   IFS=:; set-f             #split on :; disable filename gen
    set +f -- $PATH          #store split array, enable filename gen after
    IFS=                     #disable field splitting
    for p do for x in ${p:+"$p/"$g}
          do command -v "$x"
    done;done
)                            #done in subshell to avoid affecting current shell

Последние части не комментируются, потому что здесь они лучше объяснены.

  • for p do - Первый цикл for итеративно присваивает $ p значение каждого позиционного параметра в «$ @» оболочки массив , которые устанавливают как разделенное по полям расширение $ PATH , разделенное на : двоеточия.

  • for x в $ {p: + "$ p /" $ g} - Внутренний цикл for итеративно устанавливает $ x для каждого (если any) расширений $ {p: + "$ p /" $ g} - то есть, он не выполняет итерации вообще ничего, если только $ p не является оба установлены и не равны нулю. Это важно, потому что :: или ведущий : будет разделен на пустые поля, и, таким образом, два цикла строго соответствуют ] $ PATH spec (как указано выше) , не подтверждая поля нулевой длины .

  • Важно отметить, что из-за способа разделения $ PATH , когда генерация имени файла отключена, и «$ p /» $ g разрешается, пока он включен, но разделение полей было отключен, ни один из элементов в $ PATH не может расширяться до чего-либо, кроме их полей, разделенных на : (независимо от того, какие другие символы они могут содержать) , и ни одно из значений не может for "$ p /" $ g расширяется до чего угодно, кроме самого себя или любых имен файлов, которые могут совпадать (независимо от любых символов в $ p или отличных от символов сопоставления с образцом $ g может содержать) .

  • команда - и последняя команда печатает в стандартном формате только те значения для $ x , которые являются исполняемыми командами.

Вот все, что заключено в функцию оболочки с дополнительной возможностью обработки нескольких $ g аргументов:

glob_path()( 
    for g do IFS=:; set -f
          set +f -- ${PATH:-.}; IFS=
          for p do for x in ${p:+"$p/"$g}
                do command -v "$x"
    done; done; done
)

Это должно дать вам список исполняемых файлов, соответствующих каждому аргументу, который вы передаете, напечатанный по одному на каждый Строка упорядочена сначала по порядку аргументов, затем по приоритету $ PATH и в последнюю очередь по порядку сортировки вашего языкового стандарта. Он не должен давать сбоев при переводе строки или специальных символах в именах путей или шаблонах глобусов, которые вы ему передаете. Его можно изменить (см. Историю редактирования здесь) , чтобы точно заполнить массив оболочки «$ @» одним исполняемым файлом для каждого позиционного параметра.

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

glob_path()( 
    for g do IFS=:; set -f
          set +f -- ${PATH:-.}; IFS=
          for p do for x in ${p+:"$p/"$g}
                do command -v "$x" &&
                   command "$x"    &&
                   break 2
    done; done; done
)

Это портативное средство POSIX для поиска вашего glob, но некоторым оболочкам даже не нужен второй цикл for g ... . В bash , например, это также будет работать как ...

glob_path()( 
    for g do IFS=:; set -f
          set +f -- ${PATH:-.}; IFS=
          for p do command -v ${p:+"$p/"$g}
    done; done
)

... который по-прежнему перечисляет все совпадения исполняемых глобусов для всех аргументов и для каждого элемента в $ PATH независимо от о том, содержат ли какие-либо из этих элементов или шаблонов глобусов символы новой строки, специальные символы и т. д.

Вы можете использовать это как:

glob_path '?sh' '??sh'       #I'd rather not install libreoffice

... который для меня печатает ...

/usr/bin/ksh
/usr/bin/rsh
/usr/bin/ssh
/usr/bin/zsh
/usr/local/bin/dash
/usr/local/bin/yash
/usr/bin/bash
/usr/bin/bssh
/usr/bin/chsh
/usr/bin/dash
/usr/bin/mksh
/usr/bin/posh
/usr/bin/slsh
/usr/bin/yash

Как уже обсуждалось, функция glob_path интерпретирует переменную среды $ PATH , поскольку в спецификации указано, что строго соответствующее приложение должно игнорировать начальные, конечные или последовательные : встречается в значении $ PATH , но интерпретирует пустой или неустановленный $ PATH как означающий . .

Однако, если вам нужна эта устаревшая функция, функцию можно было бы написать:

glob_path()(
    for g do IFS=:; set -f
          set +f -- ${0+$PATH:}; IFS=
          for p do for x in "${p:-.}/"$g
                do command -v "$x"
    done; done; done
)

... которая интерпретировала бы все вхождения начальных, конечных или двух последовательных : двоеточий как означающих . (и поэтому ищите . столько раз, сколько компонент нулевой длины $ PATH появляется в значении $ PATH ) , но это не совсем соответствует.

0
27.01.2020, 20:18

Теги

Похожие вопросы