variable - Überprüfen Sie, ob ein Programm von einem Bash-Skript existiert




bash script pass variable (20)

Antworten

POSIX-kompatibel:

command -v <the_command>

Für bash spezifische Umgebungen:

hash <the_command> # For regular commands. Or...
type <the_command> # To check built-ins and keywords

Erläuterung

Vermeiden Sie which . Es ist nicht nur ein externer Prozess, den Sie starten, um sehr wenig zu tun (das bedeutet, dass Built-Ins wie hash , type oder command viel billiger sind), Sie können sich auch auf die Built-Ins verlassen, um das zu tun, was Sie wollen variieren leicht von System zu System.

Warum kümmern?

  • Viele Betriebssysteme haben eine, die nicht einmal einen Exit-Status setzt , was bedeutet, if which foo nicht einmal dort funktioniert und immer meldet, dass foo existiert, auch wenn es nicht funktioniert (beachten Sie, dass einige POSIX-Shells zu tun scheinen) dies auch für hash ).
  • Viele Betriebssysteme machen benutzerdefinierte und böse Sachen wie die Ausgabe ändern oder sogar in den Paketmanager einhaken.

Also, benutze which . Verwenden Sie stattdessen eines von diesen:

$ 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; }

(Minor side-note: einige werden vorschlagen 2>&- ist das gleiche 2>/dev/null aber kürzer - das ist nicht wahr . 2>&- schließt FD 2, was einen Fehler im Programm verursacht, wenn es versucht, in stderr zu schreiben , was sich sehr davon unterscheidet, erfolgreich darauf zu schreiben und die Ausgabe zu verwerfen (und gefährlich!))

Wenn Ihr Hash-Bang /bin/sh ist, sollten Sie sich darum kümmern, was POSIX sagt. type Exit-Codes von type und hash sind von POSIX nicht besonders gut definiert, und der hash Befehl wird erfolgreich beendet, wenn der Befehl nicht existiert (habe den type noch nicht gesehen). command des command ist von POSIX gut definiert, so dass einer wahrscheinlich der sicherste ist.

Wenn Ihr Skript jedoch bash verwendet, sind POSIX-Regeln nicht mehr wichtig und sowohl type als auch hash werden absolut sicher zu verwenden. type nun ein -P , um nur den PATH zu suchen und hash hat den Nebeneffekt, dass die Position des Befehls gehashed wird (für eine schnellere Suche beim nächsten Mal), was normalerweise eine gute Sache ist, da Sie wahrscheinlich nach seiner Existenz suchen um es tatsächlich zu benutzen.

Als einfaches Beispiel, hier ist eine Funktion, die gdate falls sie existiert, ansonsten date :

gnudate() {
    if hash gdate 2>/dev/null; then
        gdate "[email protected]"
    else
        date "[email protected]"
    fi
}

Wie würde ich bestätigen, dass ein Programm existiert, so dass entweder ein Fehler zurückgegeben und beendet wird oder mit dem Skript fortgefahren wird?

Es scheint, als ob es leicht sein sollte, aber es hat mich gestampft.


Das folgende ist eine portable Möglichkeit zu überprüfen, ob ein Befehl in $PATH und ausführbar ist:

[ -x "$(command -v foo)" ]

Beispiel:

if ! [ -x "$(command -v git)" ]; then
  echo 'Error: git is not installed.' >&2
  exit 1
fi

Die ausführbare Überprüfung ist erforderlich, da Bash eine nicht ausführbare Datei zurückgibt, wenn keine ausführbare Datei mit diesem Namen in $PATH .

Beachten Sie außerdem, dass wenn eine nicht ausführbare Datei mit dem gleichen Namen wie die ausführbare Datei in $PATH früher existiert, der erste $PATH , obwohl letzterer ausgeführt wird. Dies ist ein Bug und verletzt den POSIX-Standard. [ Fehlerbericht ] [ Standard ]

Außerdem schlägt dies fehl, wenn der gesuchte Befehl als Alias ​​definiert wurde.


Die Hash-Variante hat eine Fallstricke: In der Befehlszeile können Sie zum Beispiel eingeben

one_folder/process

Prozess ausgeführt haben. Dazu muss der Elternordner von one_folder in $ PATH sein . Aber wenn Sie versuchen, diesen Befehl zu hashen, wird er immer erfolgreich sein:

hash one_folder/process; echo $? # will always output '0'

Erweiternd auf @ lhunaths und @ GregVs Antworten, hier ist der Code für die Leute, die diesen Check einfach in eine if Anweisung einfügen wollen:

exists()
{
  command -v "$1" >/dev/null 2>&1
}

So verwenden Sie es:

if exists bash; then
  echo 'Bash exists!'
else
  echo 'Your system does not have Bash'
fi

Für Interessierte funktioniert keine der oben genannten Methoden, wenn Sie eine installierte Bibliothek erkennen möchten. Ich stelle mir vor, dass Sie entweder den Pfad physisch überprüfen (möglicherweise für Header-Dateien und so), oder etwas Ähnliches (wenn Sie sich auf einer Debian-basierten Distribution befinden):

dpkg --status libdb-dev | grep -q not-installed

if [ $? -eq 0 ]; then
    apt-get install libdb-dev
fi

Wie Sie oben sehen können, bedeutet eine Antwort "0" aus der Abfrage, dass das Paket nicht installiert ist. Dies ist eine Funktion von "grep" - eine "0" bedeutet, dass eine Übereinstimmung gefunden wurde, eine "1" bedeutet, dass keine Übereinstimmung gefunden wurde.


Ich benutze das, weil es sehr einfach ist:

if [ `LANG=C type example 2>/dev/null|wc -l` = 1 ];then echo exists;else echo "not exists";fi

oder

if [ `LANG=C type example 2>/dev/null|wc -l` = 1 ];then
echo exists
else echo "not exists"
fi

Es verwendet Shell-Built-In und Programm Echo-Status zu stdout und nichts zu stderr auf der anderen Seite, wenn ein Befehl nicht gefunden wird, gibt es nur Status zu stderr.


Ich habe nie die obigen Lösungen bekommen, um an der Box zu arbeiten, auf die ich Zugriff habe. Zum einen wurde Typ installiert (was mehr tut). Also wird die eingebaute Direktive benötigt. Dieser Befehl funktioniert für mich:

if [ `builtin type -p vim` ]; then echo "TRUE"; else echo "FALSE"; fi

Ich konnte keine der Lösungen zum Arbeiten bekommen, aber nachdem ich sie ein wenig überarbeitet hatte, kam ich auf diese Idee. Was für mich funktioniert:

dpkg --get-selections | grep -q linux-headers-$(uname -r)

if [ $? -eq 1 ]; then
        apt-get install linux-headers-$(uname -r)
fi

Ich stimme der Verwendung von "Befehl-V". ZB so:

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

Ich stimme mit Lhunath überein, um deren Verwendung zu verhindern, und seine Lösung ist für BASH-Benutzer absolut gültig. Um jedoch portabler zu sein, sollte stattdessen der command -v verwendet werden:

$ command -v foo >/dev/null 2>&1 || { echo "I require foo but it's not installed.  Aborting." >&2; exit 1; }

Befehl command ist POSIX-kompatibel, siehe hier für seine Spezifikation: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/command.html

Hinweis: Der type ist POSIX-kompatibel, der type -P jedoch nicht.


Skript

#!/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"'

Ergebnis

✘ [ABRT]: notacmd: command does not exist
hits    command
   0    /usr/bin/bash
Fin.

Um hash , wie @lhunath es vorschlägt , in einem Bash-Skript:

hash foo &> /dev/null
if [ $? -eq 1 ]; then
    echo >&2 "foo not found."
fi

Dieses Skript führt einen hash und prüft dann, ob der Exit-Code des letzten Befehls, der in $? , ist gleich 1 . Wenn hash nicht foo , wird der Exit-Code 1 . Wenn foo vorhanden ist, wird der Beendigungscode 0 .

&> /dev/null leitet den Standardfehler und die Standardausgabe von hash so dass sie nicht auf dem Bildschirm erscheint, und echo >&2 schreibt die Nachricht in den Standardfehler.


Versuchen Sie es mit:

test -x filename

oder

[ -x filename ]

Aus der Bash-Manpage unter Bedingte Ausdrücke :

 -x file
          True if file exists and is executable.

Warum nicht Bashins verwenden, wenn du kannst?

which programname

...

type -P programname

Wenn Sie nach dem Vorhandensein eines Programms suchen, werden Sie es wahrscheinlich später trotzdem ausführen. Warum nicht versuchen, es überhaupt zu starten?

if foo --version >/dev/null 2>&1; then
    echo Found
else
    echo Not found
fi

Es ist eine vertrauenswürdigere Überprüfung, dass das Programm ausgeführt wird, als nur PATH-Verzeichnisse und Dateiberechtigungen zu betrachten.

Außerdem können Sie einige nützliche Ergebnisse aus Ihrem Programm erhalten, z. B. die Version.

Natürlich sind die Nachteile, dass einige Programme schwer zu starten sind und einige haben keine --version Option, um sofort (und erfolgreich) zu beenden.


Wenn ihr die Dinge oben / unten nicht zur Arbeit bringt und Haare aus dem Rücken zieht, versucht, den gleichen Befehl mit bash -c auszuführen. Schau dir dieses somnambule Delirium an, das passiert wirklich, wenn du $ (Unterbefehl) ausführst:

Zuerst. Es kann Ihnen völlig unterschiedliche Ausgabe geben.

$ command -v ls
alias ls='ls --color=auto'
$ bash -c "command -v ls"
/bin/ls

Zweite. Es kann Ihnen überhaupt keine Ausgabe geben.

$ command -v nvm
nvm
$ bash -c "command -v nvm"
$ bash -c "nvm --help"
bash: nvm: command not found

mein Setup für einen Debian-Server. Ich hatte ein Problem, wenn mehrere Pakete den gleichen Namen enthalten. zum Beispiel apache2. Das war meine Lösung.

function _apt_install() {
    apt-get install -y $1 > /dev/null
}

function _apt_install_norecommends() {
    apt-get install -y --no-install-recommends $1 > /dev/null
}
function _apt_available() {
    if [ `apt-cache search $1 | grep -o "$1" | uniq | wc -l` = "1" ]; then
        echo "Package is available : $1"
        PACKAGE_INSTALL="1"
    else
        echo "Package $1 is NOT available for install"
        echo  "We can not continue without this package..."
        echo  "Exitting now.."
        exit 0
    fi
}
function _package_install {
    _apt_available $1
    if [ "${PACKAGE_INSTALL}" = "1" ]; then
        if [ "$(dpkg-query -l $1 | tail -n1 | cut -c1-2)" = "ii" ]; then
             echo  "package is already_installed: $1"
        else
            echo  "installing package : $1, please wait.."
            _apt_install $1
            sleep 0.5
        fi
    fi
}

function _package_install_no_recommends {
    _apt_available $1
    if [ "${PACKAGE_INSTALL}" = "1" ]; then
        if [ "$(dpkg-query -l $1 | tail -n1 | cut -c1-2)" = "ii" ]; then
             echo  "package is already_installed: $1"
        else
            echo  "installing package : $1, please wait.."
            _apt_install_norecommends $1
            sleep 0.5
        fi
    fi
}

Überprüfen Sie auf mehrere Abhängigkeiten und informieren Sie den Status für die Endbenutzer

for cmd in "latex" "pandoc"; do
  printf "%-10s" "$cmd"
  if hash "$cmd" 2>/dev/null; then printf "OK\n"; else printf "missing\n"; fi
done

Beispielausgabe:

latex     OK
pandoc    missing

Stellen Sie die 10 auf die maximale Befehlslänge ein. Nicht automatisch, weil ich keinen nicht ausführlichen Weg sehe, es zu tun.


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

checkexists() {
    while [ -n "$1" ]; do
        [ -n "$(which "$1")" ] || echo "$1": command not found
        shift
    done
}




shell