Jak mogę sprawdzić, czy aplikacja istnieje w $ PATH?

19

Próbuję napisać wszystkie moje shskrypty startowe / env do pracy z tak dużą ilością OSUSZANIA i jak najwięcej: „działa na każdym * nix, w którym go klonuję”, jak to możliwe. Oznacza to upewnienie się, że jeśli spróbuję uruchomić kod, którego tam nie ma, kod nie działa płynnie. W tym celu muszę móc sprawdzić, czy istnieją programy. Wiem, jak sprawdzić, czy plik istnieje, ale nie jestem pewien, jak sprawdzić, czy aplikacja jest wykonywalna na ścieżce. Wolę używać $ PATH, ponieważ niektóre z nich muszą pracować na arch, ubuntu i centos. Niektóre mogą być zainstalowane w moim katalogu głównym, na systemach, na których nie mam roota, inne mogą nie zostać zainstalowane, a jeszcze inne mogą być zainstalowane na ścieżkach systemowych.

ksenoterracid
źródło
2
Ta SO odpowiedź jest tą, którą dodałem do zakładek na takie pytania.
jw013,

Odpowiedzi:

19

Zastosowanie type commandname. Zwraca true, jeśli commandnamejest cokolwiek wykonywalnego: alias, funkcja, wbudowane lub zewnętrzne polecenie (sprawdzone w $PATH). Alternatywnie, użyj command commandnamezwracanej wartości true, jeśli commandnamejest to polecenie wbudowane lub zewnętrzne (wyszukiwane w $PATH).

exists () {
  type "$1" >/dev/null 2>/dev/null
}

Istnieje kilka wariantów sh (zdecydowanie wcześniejszych niż POSIX; wiem o /bin/shOSF1 ≤3.x i niektórych wersjach powłoki Almquist we wczesnych wersjach NetBSD i kilku dystrybucjach Linuksa z XX wieku), w których typezawsze zwraca 0 lub nie istnieć. Nie sądzę, aby jakikolwiek system był dostarczany z tym tysiącleciem. Jeśli kiedykolwiek je spotkasz, możesz skorzystać z funkcji $PATHręcznego wyszukiwania :

exists () { (
    IFS=:
    for d in $PATH; do
      if test -x "$d/$1"; then return 0; fi
    done
    return 1
) }

Ta funkcja jest ogólnie przydatna, jeśli chcesz wykluczyć wbudowane funkcje i funkcje i wyszukać nazwę w $PATH. Większość powłok ma do tego wbudowane command -v, choć jest to stosunkowo nowy dodatek do POSIX (wciąż opcjonalny od POSIX: 2004). Jest to w zasadzie wersja przyjazna dla programistów type: drukuje pełną ścieżkę do pliku wykonywalnego $PATH, samą nazwę dla funkcji wbudowanej lub funkcji oraz definicję aliasu dla aliasu.

exists_in_path () {
  case $(command -v -- "$1") in
    /*) return 0;;
    alias\ *) return 1;; # alias
    *) return 1;; # built-in or function
  esac
}

Ksh, bash i zsh również muszą type -pwyszukiwać tylko pliki wykonywalne $PATH. Zauważ, że w bash, zwracanym statusem type -p foojest 0, jeśli foojest wbudowaną funkcją lub; jeśli chcesz przetestować plik wykonywalny w $PATH, musisz sprawdzić, czy dane wyjściowe nie są puste. type -pnie ma w POSIX; na przykład jesion Debiana (który jest /bin/shna Ubuntu) go nie ma.

Gilles „SO- przestań być zły”
źródło
@Gilles, czy to (lub coś podobnego) if [ type keychain ]; thennie zadziała? Mam błąd. /home/xenoterracide/.zshrc:84: parse error: condition expected: typePrzypuszczam, że mógłbym napisać, że funkcja istnieje ... Po prostu pomyślałem, że może to być prostsze w pewnym sensie ...
Xenoterracide
@xenoterracide: Upuść nawiasy!
Gilles „SO- przestań być zły”
Myślę, że szukasz if type $APP >/dev/null 2>/dev/null; then ...Nie chcesz [].
Steven D
4
Bah, wiedziałem, że powinienem się odświeżyć. Ponownie pobity przez Gillesa!
Steven D
type -pjeśli konkretnie szukasz polecenia w $PATH(nie aliasy, funkcje lub wbudowane).
ephemient
1

Jeśli szukasz tylko programów zewnętrznych, możesz także ich użyć. Nie wiem jednak, jak to jest przenośne.

Kim
źródło
3
Teoretycznie jest mniej przenośny niż typelub command; whichna przykład nie ma go w POSIX. W praktyce whichistnieje prawie wszędzie, ale w niektórych miejscach (gdzie jest zaimplementowany jako skrypt csh) używa innej ścieżki (z powodu a .cshrc), co nie pozwala na osiągnięcie celu.
Gilles „SO- przestań być zły”