Как я могу проверить, что программа существует, таким образом, что она либо возвратит ошибку и завершится, либо продолжит работу со сценарием?
Кажется, что это должно быть легко, но это меня озадачило.
POSIX-совместимый:
command -v <the_command>
Для bash
конкретных сред:
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, что сильно отличается от успешной записи в нее и отбрасывания вывода (и это опасно!))
Если ваш hash bang is /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
}
Потрясающий ответ и объяснение от @lhunath. Спас мой день. Я немного расширил это. Не мог контролировать себя, разделяя это - надеясь, что это может быть полезно для кого-то. Если кто-то должен проверить (массив) нескольких программ, вот быстрый фрагмент.
Что он делает? (1) Читать массив программ. (2) Показать сообщение для неудачной программы. (3) Предложить пользователю продолжить (принудительный цикл) опции y / n для проверки остальных программ.
#!/bin/bash
proginstalldir=/full/dir/path/of/installation
progsbindir=$proginstalldir/bin
echo -e "\nMy install directory - $proginstalldir"
echo -e "My binaries directory - $progsbindir"
VerifyInstall () {
clear
myprogs=( program1 program2 program3 program4 program5 programn );
echo -e "\nValidation of my programs started...."
for ((i=0; i<${#myprogs[@]}; i++)) ; do
command -v $progsbindir/${myprogs[i]} >/dev/null && echo -e "Validating....\t${myprogs[i]}\tSUCCESSFUL" || { echo -e "Validating.... \t${myprogs[i]}\tFAILED" >&2;
while true; do
printf "%s: " "ERROR.... Validation FAILED for ${myprogs[i]} !!!! Continue?"; read yn;
case $yn in [Yy] ) echo -e "Please wait..." ; break;;
[Nn]) echo -e "\n\n#################################\n## Validation Failed .. !! ##\n#################################\n\n" ; exit 1; break;;
*) echo -e "\nPlease answer y or n then press Enter\n"; esac; done; >&2; }; done
sleep 2
}
VerifyInstall
Если вы, ребята, не можете заставить вещи выше / ниже работать и выдергивать волосы из спины, попробуйте выполнить ту же команду, используя bash -c
. Достаточно взглянуть на этот сомнамбулярный бред, это то, что действительно происходит, когда вы запускаете $ (подкоманда):
Сначала. Это может дать вам совершенно другой результат.
$ command -v ls
alias ls='ls --color=auto'
$ bash -c "command -v ls"
/bin/ls
Второе. Это может вообще не дать вам результата.
$ command -v nvm
nvm
$ bash -c "command -v nvm"
$ bash -c "nvm --help"
bash: nvm: command not found
Я использую это, потому что это очень просто:
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
Он использует встроенную оболочку и программный эхо-статус для stdout и ничего для stderr другой стороны, если команда не найдена, она отображает статус только для stderr.
Сценарий
#!/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 || return 1
hash $mycomm 2>/dev/null || \
printf "\xe2\x9c\x98 [ABRT]: $mycomm: command does not exist\n"; return 1;
}
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.
Здесь есть множество вариантов, но я не удивился, когда не было быстрых однострочников, это то, что я использовал в начале своих сценариев:
[[ "$(command -v mvn)" ]] || { echo "mvn is not installed" 1>&2 ; exit 1; }
[[ "$(command -v java)" ]] || { echo "java is not installed" 1>&2 ; exit 1; }
это основано на выбранном здесь ответе, а другой источник (а я немного поиграюсь).
надеюсь, что это будет полезно для других.
Я должен был проверить, был ли установлен git
как часть развертывания нашего CI-сервера. Мой последний скрипт bash был следующим (сервер Ubuntu):
if ! builtin type -p git &>/dev/null; then
sudo apt-get -y install git-core
fi
Надеюсь, что это поможет кому-то еще!
sudo
: без условного выражения это всегда останавливалось бы и просило бы пароль (если Вы недавно не сделали sudo). BTW, может быть полезно сделать sudo -p "Type your password to install missing git-core: "
так подсказка doesn' t прибывают внезапно.
– Beni Cherniavsky-Paskin
16.11.2012, 01:33
Если нет внешней команды 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 с использованием Bash 4.2.24 (2) command -v ls
не соответствует перемещению /bin/ls-temp
.
Хэш-вариант имеет один подводный камень: например, в командной строке вы можете ввести
one_folder/process
, чтобы процесс был выполнен. Для этого родительская папка one_folder должна быть в $ PATH . Но когда вы попытаетесь хешировать эту команду, она всегда будет успешной:
hash one_folder/process; echo $? # will always output '0'
Я согласен с 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; }
Команда command
совместима с POSIX, ее спецификация приведена здесь: http://pubs.opengroup.org /onlinepubs/9699919799/utilities/command.html
Примечание: type
соответствует POSIX, но type -P
- нет.
&>/dev/null
перенаправления. Однако я соглашаюсь с Вами, что действительно имеет значение, мобильность, I' ve отредактировал мой ответ соответственно, теперь с помощью стандарта sh перенаправление >/dev/null 2>&1
.
– GregV
05.03.2012, 23:58
Это зависит от того, хотите ли вы узнать, существует ли он в одном из каталогов в переменной $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
программа.
Попробуйте использовать:
test -x filename
или
[ -x filename ]
Из справочной страницы bash в разделе Условные выражения :
-x file True if file exists and is executable.
Я никогда не заставлял вышеуказанные решения работать на коробке, к которой у меня есть доступ. Для одного типа был установлен (делает то, что делает больше). Так что встроенная директива необходима. Эта команда работает для меня:
if [ `builtin type -p vim` ]; then echo "TRUE"; else echo "FALSE"; fi
Команда which
может быть полезна. человек, который
Возвращает 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 exe-
cutable
2 if an invalid option is specified
Приятно то, что он вычисляет если исполняемый файл доступен в той среде, в которой он запущен, - это избавляет от нескольких проблем ...
-Adam
Проверка на наличие нескольких зависимостей и информирование конечных пользователей о состоянии
for cmd in latex pandoc; do
printf '%-10s' "$cmd"
if hash "$cmd" 2>/dev/null; then
echo OK
else
echo missing
fi
done
Пример вывода:
latex OK
pandoc missing
Настройте 10
на максимальную длину команды , Не автоматический, потому что я не вижу не многословного способа POSIX сделать это: Как выровнять столбцы разделенной пробелами таблицы в Bash?
hash foo 2>/dev/null
: работает с Zsh, Bash, Dash и Ash.
type -p foo
: кажется, что он работает с zsh, bash и ash (busybox), но не с dash (интерпретирует -p
как аргумент).
command -v foo
: работает с zsh, bash, dash, но не с ash (busybox) (-ash: command: not found
).
Также обратите внимание, что builtin
недоступно с ash
и dash
.
GIT=/usr/bin/git # STORE THE RELATIVE PATH
# GIT=$(which git) # USE THIS COMMAND TO SEARCH FOR THE RELATIVE PATH
if [[ ! -e $GIT ]]; then # CHECK IF THE FILE EXISTS
echo "PROGRAM DOES NOT EXIST."
exit 1 # EXIT THE PROGRAM IF IT DOES NOT
fi
# DO SOMETHING ...
exit 0 # EXIT THE PROGRAM IF IT DOES
Я бы просто попытался вызвать программу, например, с помощью --version
или --help
и , чтобы проверить, была ли команда выполнена успешно или нет
Используется с set -e
скрипт завершится, если программа не найдена, и вы получите осмысленное сообщение об ошибке:
#!/bin/bash
set -e
git --version >> /dev/null
2>&-
(" близкий дескриптор выходного файла 2" который является stderr) , имеет тот же результат как2> /dev/null
; 2)>&2
ярлык для1>&2
, который можно распознать как " перенаправьте stdout к stderr". посмотрите Усовершенствованное Руководство по созданию сценариев Bash i/o страница перенаправления для большего количества информации. – mikewaters 22.12.2011, 08:48while read element ; do .. done <<< $(echo ${ArrayVar[*]})
,for word in $(fgrep -l $ORIGINAL *.txt)
,ls -l "$directory" | sed 1d
, {{для вseq $BEGIN $END
}}... Многие попытались связаться с авторами и предложить улучшения, но it' s никакая Wiki и запросы приземлились на глухие уши. – lhunath 13.06.2013, 10:00