Что такое "программа"? Включает ли он функции и псевдонимы? whichвозвращает истину за это. typeбез аргументов дополнительно вернет true для зарезервированных слов и встроенных команд оболочки. Если «программа» означает «исполняемый в $PATH», то посмотрите этот ответ .
hash <the_command># For regular commands. Or...
type <the_command># To check built-ins and keywords
объяснение
Избегайте which. Мало того , что внешний процесс вы запуск для этого очень мало ( это означает , встроенные команды нравится hash, typeили commandэто намного дешевле), вы также можете полагаться на встроенные команды на самом деле делать то , что вы хотите, в то время как влияние внешних команд может легко изменяться от система в систему.
Зачем это нужно?
Многие операционные системы имеют функцию which, которая даже не устанавливает состояние выхода , то есть if which fooона даже не будет работать и всегда будет сообщать о fooсуществовании, даже если это не так (обратите внимание, что некоторые оболочки POSIX, похоже, hashтоже делают это ).
Многие операционные системы заставляют whichделать нестандартные и злые вещи, например, изменять вывод или даже подключаться к менеджеру пакетов.
Так что не используйте which. Вместо этого используйте один из них:
$ command -v foo >/dev/null 2>&1||{ echo >&2"I require foo but it's not installed. Aborting."; exit 1;}
$ type foo >/dev/null 2>&1||{ echo >&2"I require foo but it's not installed. Aborting."; exit 1;}
$ hash foo 2>/dev/null ||{ echo >&2"I require foo but it's not installed. Aborting."; exit 1;}
(Незначительное замечание: некоторые будут предлагать 2>&-то же самое, 2>/dev/nullно короче - это не соответствует действительности . 2>&-Закрывает FD 2, который вызывает ошибку в программе, когда она пытается записать в stderr, что сильно отличается от успешной записи в нее и отбрасывания вывода (и опасно!))
Если у вас есть хэш-бэнг, /bin/shто вам нужно знать, что говорит POSIX. typeи hashкоды выхода не очень хорошо определены в POSIX, и hashсчитается, что они успешно завершаются, когда команда не существует (еще не видела этого type). commandСостояние выхода хорошо определено POSIX, так что, вероятно, это самый безопасный для использования.
Если использование сценариев , bashхотя, правила POSIX не имеет значения , больше , и как typeи hashстановятся совершенно безопасны для использования. typeтеперь имеет -Pвозможность поиска только PATHи hashимеет побочный эффект, заключающийся в том, что расположение команды будет хэшировано (для более быстрого поиска в следующий раз, когда вы ее используете), что, как правило, хорошо, так как вы, вероятно, проверяете его существование, чтобы реально использовать его ,
В качестве простого примера, вот функция, которая запускается, gdateесли она существует, в противном случае date:
gnudate(){if hash gdate 2>/dev/null;then
gdate "$@"else
date "$@"fi}
@Geert: часть &> / dev / null скрывает сообщение type, которое выдается, когда foo не существует. > & 2 на эхо-сигнале обеспечивает отправку сообщения об ошибке в стандартную ошибку вместо стандартного вывода; потому что это соглашение. Они оба появляются на вашем терминале, но стандартная ошибка определенно является предпочтительным выходом для сообщений об ошибках и неожиданных предупреждений.
Для тех, кто не знаком с «продвинутым» перенаправлением ввода / 2>&-вывода в bash: 1) («закрыть дескриптор выходного файла 2», который является stderr), имеет тот же результат, что и 2> /dev/null; 2) >&2ярлык для 1>&2, который вы можете распознать как «перенаправить стандартный вывод в stderr». Для получения дополнительной информации см. Страницу перенаправления ввода-вывода Advanced Bash Scripting Guide .
mikewaters
9
@mikewaters АБС выглядит довольно продвинутым и описывает широкий диапазон функциональных возможностей командной строки bash и non-bash, но во многих аспектах он очень небрежен и не следует хорошей практике. У меня недостаточно места в этом комментарии, чтобы написать рецензию; но я могу вставить несколько случайных примеров BAD кода: while read element ; do .. done <<< $(echo ${ArrayVar[*]}), for word in $(fgrep -l $ORIGINAL *.txt), ls -l "$directory" | sed 1d , {{для а seq $BEGIN $END}}, ... Многие пытались связаться с авторами и предложить улучшения , но это не вики и запросы высадились на глухие уши.
13
56
@mikewaters 2>&-это не то же самое, что 2>/dev/null. Первый закрывает дескриптор файла, а второй просто перенаправляет его на /dev/null. Вы можете не увидеть ошибку, потому что программа пытается сообщить вам на stderr, что stderr закрыт.
nyuszika7h
577
Ниже представлен переносимый способ проверить, существует ли команда $PATHи является ли она исполняемой:
[-x "$(command -v foo)"]
Пример:
if![-x "$(command -v git)"];then
echo 'Error: git is not installed.'>&2
exit 1fi
Проверка исполняемого файла необходима, потому что bash возвращает неисполняемый файл, если в нем не найдено исполняемого файла с таким именем $PATH.
Также обратите внимание, что если ранее не существует исполняемого файла с тем же именем, что и у исполняемого файла $PATH, dash возвращает первый, даже если последний будет выполнен. Это ошибка, которая нарушает стандарт POSIX. [ Отчет об ошибке ] [ Стандарт ]
Кроме того, произойдет сбой, если искомая команда была определена как псевдоним.
Будет ли command -vпуть даже для неисполняемого файла? То есть -x действительно нужен?
einpoklum
5
@einpoklum -xпроверяет, является ли файл исполняемым, и это был вопрос.
Кен Шарп
3
@KenSharp: Но это кажется излишним, поскольку commandсамо по себе будет проверять его исполняемость - не так ли?
einpoklum
13
@einpoklum Да, это необходимо. На самом деле, даже это решение может сломаться в одном крайнем случае. Спасибо, что обратили на это мое внимание. dash, bash и zsh пропускают неисполняемые файлы $PATHпри выполнении команды. Тем не менее, поведение command -vочень противоречиво. В dash он возвращает первый соответствующий файл $PATH, независимо от того, исполняемый он или нет. В bash он возвращает первое совпадение исполняемого файла $PATH, но если его нет, он может вернуть неисполняемый файл. А в zsh он никогда не вернет неисполняемый файл.
nyuszika7h
5
Насколько я могу судить, dashединственный из этих трех не поддерживает POSIX; [ -x "$(command -v COMMANDNAME)"]будет работать в двух других. Похоже, что об этой ошибке уже сообщалось, но она еще не получила никаких ответов: bugs.debian.org/cgi-bin/bugreport.cgi?bug=874264
nyuszika7h
210
Я согласен с lhunath препятствовать использованию which, и его решение совершенно справедливо для пользователей Bash . Однако, чтобы быть более переносимым, command -vвместо этого должны использоваться:
$ command -v foo >/dev/null 2>&1||{ echo "I require foo but it's not installed. Aborting.">&2; exit 1;}
То же, что и выше - exit 1;убивает xterm, если вызывается оттуда.
пользователь неизвестен
1
Это не будет работать со стандартным sh: вы &> не действительны инструкции по перенаправлению.
января
7
@jyavenard: Вопрос помечен как bash , отсюда и более лаконичная нотация перенаправления, относящаяся к bash &>/dev/null. Тем не менее, я согласен с вами, что действительно важно, это переносимость, я соответственно отредактировал свой ответ, теперь используя стандартный sh redirect >/dev/null 2>&1.
GregV
чтобы еще больше улучшить этот ответ, я бы сделал две вещи: 1: используйте «&>», чтобы упростить его, как ответ Джоша. 2: разбить {} на дополнительную строку, поместив перед эхом вкладку, для удобства чтения
&>может быть недоступно в вашей версии Bash. Код Марчелло должен работать нормально; это делает то же самое.
Джош Стратер
3
Не работает со встроенными и зарезервированными словами: попробуйте это, например, со словом then. Посмотрите этот ответ, если вам требуется, чтобы исполняемый файл существовал в $PATH.
Том Хейл
84
Это зависит от того, хотите ли вы узнать, существует ли он в одном из каталогов в $PATHпеременной или знаете ли вы его абсолютное местоположение. Если вы хотите узнать, находится ли он в $PATHпеременной, используйте
if which programname >/dev/null;then
echo exists
else
echo does not exist
fi
иначе использовать
if[-x /path/to/programname ];then
echo exists
else
echo does not exist
fi
Перенаправление на /dev/null/в первом примере подавляет вывод whichпрограммы.
Готовность учиться и совершенствоваться должны быть вознаграждены. +1 Это чисто и просто. Единственное, что я могу добавить, это то, что это commandудается даже для псевдонимов, что может быть несколько нелогично. Проверка существования в интерактивной оболочке даст другие результаты, чем когда вы перемещаете ее в скрипт.
Палек
1
Я только что проверил и использую shopt -u expand_aliasesигнорирующие / скрывающие псевдонимы (как alias ls='ls -F'упомянуто в другом ответе) и shopt -s expand_aliasesразрешаю их через command -v. Так что, возможно, его следует установить до проверки и отменить после, хотя это может повлиять на возвращаемое значение функции, если вы не захватите и не вернете выходные данные вызова команды в явном виде.
dragon788
24
Попробуйте использовать:
test -x filename
или
[-x filename ]
Из справочной страницы Bash под условными выражениями :
hash foo &>/dev/null
if[ $?-eq 1];then
echo >&2"foo not found."fi
Этот скрипт запускается, hashа затем проверяет $?, равен ли код завершения самой последней команды, в которой хранится значение 1. Если hashне найдет foo, код выхода будет 1. Если fooприсутствует, код выхода будет 0.
&> /dev/nullперенаправляет стандартные ошибки и стандартный вывод из hashтак , что он не появляется на экране и echo >&2записывает сообщение в стандартный поток ошибок.
Почему не просто if hash foo &> /dev/null; then ...?
Бени Чернявский-Паскин
9
Я никогда не получал предыдущие ответы, чтобы работать над коробкой, к которой у меня есть доступ. Для одного typeбыл установлен (делает то, что moreделает). Так что встроенная директива необходима. Эта команда работает для меня:
if[`builtin type -p vim`];then echo "TRUE";else echo "FALSE";fi
Скобки не являются частью ifсинтаксиса, просто используйте if builtin type -p vim; then .... И обратные ссылки - действительно древний и устаревший синтаксис, $()поддерживаемый даже shво всех современных системах.
nyuszika7h
9
Проверьте наличие нескольких зависимостей и сообщите статус конечным пользователям.
for cmd in latex pandoc;do
printf '%-10s'"$cmd"if hash "$cmd"2>/dev/null;then
echo OK
else
echo missing
fidone
Недословный способ сделать это: 1) избавиться от спецификатора ширины; 2) добавить пробел после имени вашей команды printf; 3) направить ваш цикл for column -t(часть util-linux).
Патрис Левеск
8
Если вы проверите наличие программы, вы, вероятно, все равно будете запускать ее позже. Почему бы не попробовать запустить его в первую очередь?
if foo --version >/dev/null 2>&1;then
echo Foundelse
echo Not found
fi
Это более надежная проверка запуска программы, чем просто просмотр каталогов PATH и прав доступа к файлам.
Кроме того, вы можете получить полезный результат от вашей программы, например, ее версию.
Конечно, недостатки заключаются в том, что некоторые программы могут быть тяжелыми для запуска, а некоторые не имеют --versionвозможности немедленно (и успешно) выйти.
Тип -P имя программы должно быть предпочтительным, см. принятый ответ
RobertG
@RobertG Я вижу только то, что -Pэто не POSIX. Почему type -Pпредпочтительнее?
mikemaccana
Я должен был сформулировать это как «быть предпочтительным в среде bash» - так как я намеревался ответить на предыдущий комментарий, относящийся к bash. Во всяком случае, это было много лет назад - я полагаю, я должен просто снова указать вам ответ, помеченный как «принятый»
RobertG
4
Команда -vработает нормально, если для параметра установлен параметр POSIX_BUILTINS<command> , но сбой. (Он работал у меня годами, но недавно я столкнулся с тем, где он не работал.)
Я считаю следующее более надежным:
test -x $(which <command>)
Поскольку он проверяет три вещи: путь, существование и разрешение на выполнение.
Не работает test -x $(which ls)возвращает 0, как это делает test -x $(which sudo), даже если lsустановлен и работоспособный и sudoдаже не установлен в Докер контейнера я бег в.
водорослевом
@algal Вы должны использовать кавычки, я думаю, такtest -x "$(which <command>)"
JoniVR
@algal Может быть, lsэто псевдоним? Я не думаю, что это будет работать, если команда имеет параметр.
AnthonyC
3
Для тех, кто интересуется, ни одна из методологий в предыдущих ответах не работает, если вы хотите обнаружить установленную библиотеку. Я полагаю, что вам остается либо физически проверить путь (возможно, для заголовочных файлов и тому подобное), либо что-то вроде этого (если вы используете дистрибутив на основе Debian):
Как видно из вышесказанного, ответ «0» на запрос означает, что пакет не установлен. Это функция «grep» - «0» означает, что совпадение найдено, «1» означает, что совпадение не найдено.
Я бы сказал, что нет никакого портативного и 100% надежного способа из-за болтающихся aliasэс. Например:
alias john='ls --color'
alias paul='george -F'
alias george='ls -h'
alias ringo=/
Конечно, проблематично только последнее (без обид на Ринго!). Но все они действительны aliasс точки зрения command -v.
Чтобы отвергнуть висячие сообщения, такие как ringo, мы должны проанализировать выходные данные встроенной aliasкоманды оболочки и вернуться к ним ( command -vздесь не лучше alias). Для этого нет никакого переносимого решения, и даже Bash- конкретное решение довольно утомительно.
Обратите внимание, что подобное решение безоговорочно отклонит alias ls='ls -F':
Он возвращает 0, если исполняемый файл найден, и возвращает 1, если он не найден или не исполняемый:
NAME
which - locate a command
SYNOPSIS
which [-a] filename ...
DESCRIPTION
which returns the pathnames of the files which would
be executed in the current environment, had its
arguments been given as commands in a strictly
POSIX-conformant shell. It does this by searching
the PATH for executable files matching the names
of the arguments.
OPTIONS
-a print all matching pathnames of each argument
EXIT STATUS
0 if all specified commands are
found and executable
1 if one or more specified commands is nonexistent
or not executable
2 if an invalid option is specified
Приятно то, whichчто он выясняет, доступен ли исполняемый файл в среде, в whichкоторой он запущен, - это спасает несколько проблем ...
Используйте который, если вы ищете любой исполняемый файл с именем foo, но посмотрите мой ответ, если вы хотите проверить определенный файл / путь / к / a / named / foo. Также обратите внимание на то, что может быть недоступно на некоторых минимальных системах, хотя оно должно присутствовать на любой полноценной установке ...
dmckee --- ex-moderator kitten
9
Не полагайтесь на статус выхода которого. Многие операционные системы имеют функцию, которая даже не устанавливает состояние выхода, кроме 0.
Если вы, ребята / девочки, не можете получить ответы на вопросы, приведенные здесь в ответах, и вырываете волосы из спины, попробуйте выполнить ту же команду, используя bash -c . Просто посмотрите на этот сомнамбулярный бред. Вот что действительно происходит, когда вы запускаете $ (подкоманда):
Первый. Это может дать вам совершенно другой вывод.
$ command -v ls
alias ls='ls --color=auto'
$ bash -c "command -v ls"/bin/ls
Во-вторых. Это может вообще не дать вам результата.
Различия вызваны разницей между интерактивным и неинтерактивным режимами оболочки. Ваш ~ / .bashrc доступен только для чтения, когда оболочка не авторизована и интерактивна. Второй выглядит странно, потому что это должно быть вызвано разницей в переменной окружения PATH, но подоболочки наследуют среду.
Палек
В моем случае .bashrcесть [ -z "$PS1" ] && returnпредваряющий, # If not running interactively, don't do anythingпоэтому я думаю, что это причина, по которой даже явный источник bashrc в неинтерактивном режиме не помогает. Проблема может быть workarounded путем вызова сценария с ss64.com/bash/source.html оператора точка , . ./script.shно это не вещь , один хотел бы помнить , набирать каждый раз.
user619271
1
Сценарии поиска, которые не должны быть получены, - плохая идея. Все, что я пытался сказать, - это то, что ваш ответ имеет мало общего с задаваемым вопросом и имеет много общего с Bash и его (не) интерактивным режимом.
Палек
Если бы он объяснил, что происходит в этих случаях, это было бы полезным дополнением к ответу.
Палек
0
Хэш-вариант имеет одну ловушку: в командной строке вы можете, например, набрать
one_folder/process
чтобы процесс был выполнен. Для этого родительская папка one_folder должна быть в $ PATH . Но когда вы попытаетесь хешировать эту команду, она всегда будет успешной:
hash one_folder/process; echo $?# will always output '0'
«Для этого родительская папка one_folder должна быть в $PATH» - это совершенно неточно. Попробуй это. Чтобы это работало, one_folder должен быть в текущем каталоге .
Wildcard
0
Я второй использование "команда -v". Например, вот так:
md=$(command -v mkdirhier); alias md=${md:=mkdir}# bash
emacs="$(command -v emacs) -nw"|| emacs=nano
alias e=$emacs
[[-z $(command -v jed)]]&& alias jed=$emacs
Условие довольно бесполезно, по модулю время запуска для запуска apt-get, так как apt-get будет удовлетворен и завершится, если git-core уже установлен.
Трипли
3
Время его запуска не является ничтожным, но более важной мотивацией является sudo: без условия он всегда останавливается и запрашивает пароль (если вы недавно не сделали sudo). Кстати, это может быть полезно, sudo -p "Type your password to install missing git-core: "чтобы подсказка не появлялась на ровном месте.
Бени Чернявский-Паскин
0
Чтобы имитировать Bash type -P cmd, мы можем использовать POSIX-совместимый env -i type cmd 1>/dev/null 2>&1.
man env
# "The option '-i' causes env to completely ignore the environment it inherits."# In other words, there are no aliases or functions to be looked up by the type command.
ls(){ echo 'Hello, world!';}
ls
type ls
env -i type ls
cmd=ls
cmd=lsx
env -i type $cmd 1>/dev/null 2>&1||{ echo "$cmd not found"; exit 1;}
Почему за это проголосовали? В каких системах это на самом деле работает для вас? typeКажется, что builtinв большинстве оболочек, это не может работать, потому что envиспользует execvpдля запуска, commandпоэтому commandне может быть builtin(и builtinвсегда будет выполняться в той же среде). Это не может для меня bash, ksh93, zsh, busybox [a]shи dashвсе , которые обеспечивают typeкак встроенная команда.
Адриан Фрювирт
0
Если нет typeдоступных внешних команд (как само собой разумеющееся здесь ), мы можем использовать POSIX-совместимый env -i sh -c 'type cmd 1>/dev/null 2>&1':
# Portable version of Bash's type -P cmd (without output on stdout)
typep(){
command -p env -i PATH="$PATH" sh -c '
export LC_ALL=C LANG=C
cmd="$1"
cmd="`type "$cmd" 2>/dev/null || { echo "error: command $cmd not found; exiting ..." 1>&2; exit 1; }`"
[ $? != 0 ] && exit 1
case "$cmd" in
*\ /*) exit 0;;
*) printf "%s\n" "error: $cmd" 1>&2; exit 1;;
esac
' _ "$1"|| exit 1}# Get your standard $PATH value#PATH="$(command -p getconf PATH)"
typep ls
typep builtin
typep ls-temp
По крайней мере, в Mac OS X 10.6.8 (Snow Leopard) использование Bash 4.2.24 (2) command -v lsне соответствует перемещению /bin/ls-temp.
В случае , если вы хотите проверить , если программа существует , и это действительно программа, не Bash встроенной командой , то command, typeиhash не подходит для тестирования , как они все возвращения 0 статуса выхода для встроенных команд.
Например, есть время программа , которая предоставляет больше возможностей , чем время встроенного команды. Чтобы проверить, существует ли программа, я бы предложил использовать whichкак в следующем примере:
# First check if the time program exists
timeProg=`which time`if["$timeProg"=""]then
echo "The time program does not exist on this system."
exit 1fi# Invoke the time program
$timeProg --quiet -o result.txt -f "%S %U + p" du -sk ~
echo "Total CPU time: `dc -f result.txt` seconds"
rm result.txt
#!/bin/bash# Commands found in the hash table are checked for existence before being# executed and non-existence forces a normal PATH search.
shopt -s checkhash
function exists(){local mycomm=$1; shift ||return1
hash $mycomm 2>/dev/null || \
printf "\xe2\x9c\x98 [ABRT]: $mycomm: command does not exist\n";return1;}
readonly -f exists
exists notacmd
exists bash
hash
bash -c 'printf "Fin.\n"'
Результат
✘[ABRT]: notacmd: command does not exist
hits command
0/usr/bin/bash
Fin.
if[`LANG=C type example 2>/dev/null|wc -l`=1];then echo exists;else echo "not exists";fi
или
if[`LANG=C type example 2>/dev/null|wc -l`=1];then
echo exists
else echo "not exists"fi
Он использует встроенные функции оболочки и эхо-статус программ для стандартного вывода и ничего для стандартной ошибки. С другой стороны, если команда не найдена, она отображает статус только для стандартной ошибки.
which
возвращает истину за это.type
без аргументов дополнительно вернет true для зарезервированных слов и встроенных команд оболочки. Если «программа» означает «исполняемый в$PATH
», то посмотрите этот ответ .Ответы:
Ответ
POSIX-совместимый:
Для сред Bash:
объяснение
Избегайте
which
. Мало того , что внешний процесс вы запуск для этого очень мало ( это означает , встроенные команды нравитсяhash
,type
илиcommand
это намного дешевле), вы также можете полагаться на встроенные команды на самом деле делать то , что вы хотите, в то время как влияние внешних команд может легко изменяться от система в систему.Зачем это нужно?
which
, которая даже не устанавливает состояние выхода , то естьif which foo
она даже не будет работать и всегда будет сообщать оfoo
существовании, даже если это не так (обратите внимание, что некоторые оболочки POSIX, похоже,hash
тоже делают это ).which
делать нестандартные и злые вещи, например, изменять вывод или даже подключаться к менеджеру пакетов.Так что не используйте
which
. Вместо этого используйте один из них:(Незначительное замечание: некоторые будут предлагать
2>&-
то же самое,2>/dev/null
но короче - это не соответствует действительности .2>&-
Закрывает FD 2, который вызывает ошибку в программе, когда она пытается записать в stderr, что сильно отличается от успешной записи в нее и отбрасывания вывода (и опасно!))Если у вас есть хэш-бэнг,
/bin/sh
то вам нужно знать, что говорит POSIX.type
иhash
коды выхода не очень хорошо определены в POSIX, иhash
считается, что они успешно завершаются, когда команда не существует (еще не видела этогоtype
).command
Состояние выхода хорошо определено POSIX, так что, вероятно, это самый безопасный для использования.Если использование сценариев ,
bash
хотя, правила POSIX не имеет значения , больше , и какtype
иhash
становятся совершенно безопасны для использования.type
теперь имеет-P
возможность поиска толькоPATH
иhash
имеет побочный эффект, заключающийся в том, что расположение команды будет хэшировано (для более быстрого поиска в следующий раз, когда вы ее используете), что, как правило, хорошо, так как вы, вероятно, проверяете его существование, чтобы реально использовать его ,В качестве простого примера, вот функция, которая запускается,
gdate
если она существует, в противном случаеdate
:источник
2>&-
вывода в bash: 1) («закрыть дескриптор выходного файла 2», который является stderr), имеет тот же результат, что и2> /dev/null
; 2)>&2
ярлык для1>&2
, который вы можете распознать как «перенаправить стандартный вывод в stderr». Для получения дополнительной информации см. Страницу перенаправления ввода-вывода Advanced Bash Scripting Guide .while read element ; do .. done <<< $(echo ${ArrayVar[*]})
,for word in $(fgrep -l $ORIGINAL *.txt)
,ls -l "$directory" | sed 1d
, {{для аseq $BEGIN $END
}}, ... Многие пытались связаться с авторами и предложить улучшения , но это не вики и запросы высадились на глухие уши.2>&-
это не то же самое, что2>/dev/null
. Первый закрывает дескриптор файла, а второй просто перенаправляет его на/dev/null
. Вы можете не увидеть ошибку, потому что программа пытается сообщить вам на stderr, что stderr закрыт.Ниже представлен переносимый способ проверить, существует ли команда
$PATH
и является ли она исполняемой:Пример:
Проверка исполняемого файла необходима, потому что bash возвращает неисполняемый файл, если в нем не найдено исполняемого файла с таким именем
$PATH
.Также обратите внимание, что если ранее не существует исполняемого файла с тем же именем, что и у исполняемого файла
$PATH
, dash возвращает первый, даже если последний будет выполнен. Это ошибка, которая нарушает стандарт POSIX. [ Отчет об ошибке ] [ Стандарт ]Кроме того, произойдет сбой, если искомая команда была определена как псевдоним.
источник
command -v
путь даже для неисполняемого файла? То есть -x действительно нужен?-x
проверяет, является ли файл исполняемым, и это был вопрос.command
само по себе будет проверять его исполняемость - не так ли?$PATH
при выполнении команды. Тем не менее, поведениеcommand -v
очень противоречиво. В dash он возвращает первый соответствующий файл$PATH
, независимо от того, исполняемый он или нет. В bash он возвращает первое совпадение исполняемого файла$PATH
, но если его нет, он может вернуть неисполняемый файл. А в zsh он никогда не вернет неисполняемый файл.dash
единственный из этих трех не поддерживает POSIX;[ -x "$(command -v COMMANDNAME)"]
будет работать в двух других. Похоже, что об этой ошибке уже сообщалось, но она еще не получила никаких ответов: bugs.debian.org/cgi-bin/bugreport.cgi?bug=874264Я согласен с lhunath препятствовать использованию
which
, и его решение совершенно справедливо для пользователей Bash . Однако, чтобы быть более переносимым,command -v
вместо этого должны использоваться:Команда
command
соответствует POSIX. Смотрите здесь для его спецификации: команда - выполнить простую командуПримечание:
type
совместимо с POSIX, ноtype -P
это не так.источник
exit 1;
убивает xterm, если вызывается оттуда.&>/dev/null
. Тем не менее, я согласен с вами, что действительно важно, это переносимость, я соответственно отредактировал свой ответ, теперь используя стандартный sh redirect>/dev/null 2>&1
.У меня есть функция, определенная в моем .bashrc, которая делает это проще.
Вот пример того, как это используется (из моего
.bash_profile
.)источник
&>
?&>
Перенаправляет как стандартный вывод и стандартный поток ошибок вместе.&>
может быть недоступно в вашей версии Bash. Код Марчелло должен работать нормально; это делает то же самое.then
. Посмотрите этот ответ, если вам требуется, чтобы исполняемый файл существовал в$PATH
.Это зависит от того, хотите ли вы узнать, существует ли он в одном из каталогов в
$PATH
переменной или знаете ли вы его абсолютное местоположение. Если вы хотите узнать, находится ли он в$PATH
переменной, используйтеиначе использовать
Перенаправление на
/dev/null/
в первом примере подавляет выводwhich
программы.источник
Расширяя ответы @ lhunath и @ GregV, вот код для людей, которые хотят легко вставить эту проверку в
if
утверждение:Вот как это использовать:
источник
command
удается даже для псевдонимов, что может быть несколько нелогично. Проверка существования в интерактивной оболочке даст другие результаты, чем когда вы перемещаете ее в скрипт.shopt -u expand_aliases
игнорирующие / скрывающие псевдонимы (какalias ls='ls -F'
упомянуто в другом ответе) иshopt -s expand_aliases
разрешаю их черезcommand -v
. Так что, возможно, его следует установить до проверки и отменить после, хотя это может повлиять на возвращаемое значение функции, если вы не захватите и не вернете выходные данные вызова команды в явном виде.Попробуйте использовать:
или
Из справочной страницы Bash под условными выражениями :
источник
Чтобы использовать
hash
, как предполагает @lhunath , в скрипте Bash:Этот скрипт запускается,
hash
а затем проверяет$?
, равен ли код завершения самой последней команды, в которой хранится значение1
. Еслиhash
не найдетfoo
, код выхода будет1
. Еслиfoo
присутствует, код выхода будет0
.&> /dev/null
перенаправляет стандартные ошибки и стандартный вывод изhash
так , что он не появляется на экране иecho >&2
записывает сообщение в стандартный поток ошибок.источник
if hash foo &> /dev/null; then ...
?Я никогда не получал предыдущие ответы, чтобы работать над коробкой, к которой у меня есть доступ. Для одного
type
был установлен (делает то, чтоmore
делает). Так что встроенная директива необходима. Эта команда работает для меня:источник
if
синтаксиса, просто используйтеif builtin type -p vim; then ...
. И обратные ссылки - действительно древний и устаревший синтаксис,$()
поддерживаемый дажеsh
во всех современных системах.Проверьте наличие нескольких зависимостей и сообщите статус конечным пользователям.
Пример вывода:
Установите
10
максимальную длину команды. Это не автоматически, потому что я не вижу невербального способа POSIX сделать это: Как я могу выровнять столбцы разделенной пробелами таблицы в Bash?Проверьте, установлены ли некоторые
apt
пакеты,dpkg -s
и установите их иначе .См. Проверьте, установлен ли пакет apt-get, а затем установите его, если он не в Linux.
Ранее упоминалось по адресу: Как я могу проверить, существует ли программа из скрипта Bash?
источник
column -t
(часть util-linux).Если вы проверите наличие программы, вы, вероятно, все равно будете запускать ее позже. Почему бы не попробовать запустить его в первую очередь?
Это более надежная проверка запуска программы, чем просто просмотр каталогов PATH и прав доступа к файлам.
Кроме того, вы можете получить полезный результат от вашей программы, например, ее версию.
Конечно, недостатки заключаются в том, что некоторые программы могут быть тяжелыми для запуска, а некоторые не имеют
--version
возможности немедленно (и успешно) выйти.источник
hash foo 2>/dev/null
: работает с Z shell (Zsh), Bash, Dash и Ash .type -p foo
: он работает с Z shell, Bash и ash ( BusyBox ), но не с Dash (это интерпретируется-p
как аргумент).command -v foo
: работает с Z shell, Bash, Dash, но не с пеплом (BusyBox) (-ash: command: not found
).Также обратите внимание, что
builtin
не доступно с золой и чертой.источник
Используйте встроенные команды Bash, если можете:
...
источник
which
это не встроенный Bash.-P
это не POSIX. Почемуtype -P
предпочтительнее?Команда
-v
работает нормально, если для параметра установлен параметр POSIX_BUILTINS<command>
, но сбой. (Он работал у меня годами, но недавно я столкнулся с тем, где он не работал.)Я считаю следующее более надежным:
Поскольку он проверяет три вещи: путь, существование и разрешение на выполнение.
источник
test -x $(which ls)
возвращает 0, как это делаетtest -x $(which sudo)
, даже еслиls
установлен и работоспособный иsudo
даже не установлен в Докер контейнера я бег в.test -x "$(which <command>)"
ls
это псевдоним? Я не думаю, что это будет работать, если команда имеет параметр.Для тех, кто интересуется, ни одна из методологий в предыдущих ответах не работает, если вы хотите обнаружить установленную библиотеку. Я полагаю, что вам остается либо физически проверить путь (возможно, для заголовочных файлов и тому подобное), либо что-то вроде этого (если вы используете дистрибутив на основе Debian):
Как видно из вышесказанного, ответ «0» на запрос означает, что пакет не установлен. Это функция «grep» - «0» означает, что совпадение найдено, «1» означает, что совпадение не найдено.
источник
cmd; if [ $? -eq 0 ]; then
должен быть рефакторинг вif cmd; then
dpkg
илиapt
Здесь есть тонна вариантов, но я не удивился, что быстрых однострочников. Вот что я использовал в начале своих сценариев:
Это основано на выбранном ответе здесь и другом источнике.
источник
Я бы сказал, что нет никакого портативного и 100% надежного способа из-за болтающихся
alias
эс. Например:Конечно, проблематично только последнее (без обид на Ринго!). Но все они действительны
alias
с точки зренияcommand -v
.Чтобы отвергнуть висячие сообщения, такие как
ringo
, мы должны проанализировать выходные данные встроеннойalias
команды оболочки и вернуться к ним (command -v
здесь не лучшеalias
). Для этого нет никакого переносимого решения, и даже Bash- конкретное решение довольно утомительно.Обратите внимание, что подобное решение безоговорочно отклонит
alias ls='ls -F'
:источник
shopt -u expand_aliases
игнорирует / скрывает эти псевдонимы иshopt -s expand_aliases
показывает их черезcommand -v
.Это скажет в зависимости от местоположения, если программа существует или нет:
источник
Команда
which
может быть полезной. человек, которыйОн возвращает 0, если исполняемый файл найден, и возвращает 1, если он не найден или не исполняемый:
Приятно то,
which
что он выясняет, доступен ли исполняемый файл в среде, вwhich
которой он запущен, - это спасает несколько проблем ...источник
Моя установка для Debian сервера :
У меня была проблема, когда несколько пакетов содержали одно и то же имя.
Например
apache2
. Так что это было мое решение:источник
Если вы, ребята / девочки, не можете получить ответы на вопросы, приведенные здесь в ответах, и вырываете волосы из спины, попробуйте выполнить ту же команду, используя
bash -c
. Просто посмотрите на этот сомнамбулярный бред. Вот что действительно происходит, когда вы запускаете $ (подкоманда):Первый. Это может дать вам совершенно другой вывод.
Во-вторых. Это может вообще не дать вам результата.
источник
.bashrc
есть[ -z "$PS1" ] && return
предваряющий,# If not running interactively, don't do anything
поэтому я думаю, что это причина, по которой даже явный источник bashrc в неинтерактивном режиме не помогает. Проблема может быть workarounded путем вызова сценария с ss64.com/bash/source.html оператора точка ,. ./script.sh
но это не вещь , один хотел бы помнить , набирать каждый раз.Хэш-вариант имеет одну ловушку: в командной строке вы можете, например, набрать
чтобы процесс был выполнен. Для этого родительская папка one_folder должна быть в $ PATH . Но когда вы попытаетесь хешировать эту команду, она всегда будет успешной:
источник
$PATH
» - это совершенно неточно. Попробуй это. Чтобы это работало, one_folder должен быть в текущем каталоге .Я второй использование "команда -v". Например, вот так:
источник
Я должен был проверить, был ли Git установлен как часть развертывания нашего CI- сервера. Мой последний скрипт Bash был следующим (сервер Ubuntu):
источник
sudo
: без условия он всегда останавливается и запрашивает пароль (если вы недавно не сделали sudo). Кстати, это может быть полезно,sudo -p "Type your password to install missing git-core: "
чтобы подсказка не появлялась на ровном месте.Чтобы имитировать Bash
type -P cmd
, мы можем использовать POSIX-совместимыйenv -i type cmd 1>/dev/null 2>&1
.источник
type
Кажется, чтоbuiltin
в большинстве оболочек, это не может работать, потому чтоenv
используетexecvp
для запуска,command
поэтомуcommand
не может бытьbuiltin
(иbuiltin
всегда будет выполняться в той же среде). Это не может для меняbash
,ksh93
,zsh
,busybox [a]sh
иdash
все , которые обеспечиваютtype
как встроенная команда.Если нет
type
доступных внешних команд (как само собой разумеющееся здесь ), мы можем использовать POSIX-совместимыйenv -i sh -c 'type cmd 1>/dev/null 2>&1'
:По крайней мере, в Mac OS X 10.6.8 (Snow Leopard) использование Bash 4.2.24 (2)
command -v ls
не соответствует перемещению/bin/ls-temp
.источник
В случае , если вы хотите проверить , если программа существует , и это действительно программа, не Bash встроенной командой , то
command
,type
иhash
не подходит для тестирования , как они все возвращения 0 статуса выхода для встроенных команд.Например, есть время программа , которая предоставляет больше возможностей , чем время встроенного команды. Чтобы проверить, существует ли программа, я бы предложил использовать
which
как в следующем примере:источник
Я хотел получить ответ на тот же вопрос, но запустить его в Makefile.
источник
скрипт
Результат
источник
Я использую это, потому что это очень просто:
или
Он использует встроенные функции оболочки и эхо-статус программ для стандартного вывода и ничего для стандартной ошибки. С другой стороны, если команда не найдена, она отображает статус только для стандартной ошибки.
источник