Vraag Hoe controleer ik of een programma bestaat uit een Bash-script?


Hoe kan ik valideren dat een programma bestaat, op een manier die een foutmelding terugzet en afsluit, of doorgaan met het script?

Het lijkt erop dat het gemakkelijk zou moeten zijn, maar het heeft me gestoken.


1573
2018-02-26 21:52


oorsprong


antwoorden:


Antwoord

POSIX compatibel:

command -v <the_command>

Voor bash specifieke omgevingen:

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

Uitleg

vermijden which. Het is niet alleen een extern proces dat je lanceert om heel weinig te doen (wat betekent dat het gebouwd is hash, type of command zijn veel goedkoper), u kunt ook vertrouwen op de ingebouwde functies om daadwerkelijk te doen wat u wilt, terwijl de effecten van externe opdrachten gemakkelijk kunnen variëren van systeem tot systeem.

Waarom zorg?

  • Veel besturingssystemen hebben een which dat stelt zelfs geen exit-status in, wat betekent dat if which foo zal daar niet eens werken altijd rapporteer dat foo bestaat, zelfs als dat niet het geval is (merk op dat sommige POSIX-shells dit lijken te doen hash te).
  • Veel besturingssystemen maken which doe aangepaste en kwade dingen zoals het wijzigen van de uitvoer of zelfs inhaken op de pakketbeheerder.

Dus gebruik het niet which. Gebruik in plaats daarvan een van deze:

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

(Kleine kanttekening: sommigen zullen voorstellen 2>&- is hetzelfde 2>/dev/null maar korter - dit is niet waar. 2>&- sluit FD 2 af waardoor er een fout in het programma wanneer het probeert te schrijven naar stderr, wat erg verschilt van succesvol schrijven en het weggooien van de uitvoer (en gevaarlijk!))

Als je Hash-knal is /bin/sh dan zou je moeten geven om wat POSIX zegt. type en hash's exit codes zijn niet erg goed gedefinieerd door POSIX, en hash wordt gezien als succesvol afgesloten als het commando niet bestaat (dit niet gezien type nog). commandDe exit-status is goed gedefinieerd door POSIX, dus waarschijnlijk is dit de veiligste om te gebruiken.

Als je script gebruikt bash POSIX-regels maken echter niet echt meer uit en beide type en hash volkomen veilig in gebruik. type heeft nu een -P om alleen de PATH en hash heeft het neveneffect dat de locatie van het commando gehasht zal worden (voor een snellere opzoeking de volgende keer dat je het gebruikt), wat meestal een goede zaak is, omdat je waarschijnlijk het bestaan ​​ervan controleert om het daadwerkelijk te gebruiken.

Als een eenvoudig voorbeeld, hier is een functie die wordt uitgevoerd gdate als het bestaat, anders date:

gnudate() {
    if hash gdate 2>/dev/null; then
        gdate "$@"
    else
        date "$@"
    fi
}

2277
2018-03-24 12:45



Het volgende is een draagbare manier om te controleren of een commando bestaat in $PATH  en is uitvoerbaar:

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

Voorbeeld:

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

De uitvoerbare controle is nodig omdat bash een niet-uitvoerbaar bestand retourneert als er geen uitvoerbaar bestand met die naam wordt gevonden $PATH.

Merk ook op dat er eerder een niet-uitvoerbaar bestand met dezelfde naam als het uitvoerbare bestand bestaat $PATH, streepje geeft de eerste terug, ook al zou de laatste worden uitgevoerd. Dit is een bug en is in overtreding met de POSIX-standaard. [Bug report] [Standaard]

Bovendien zal dit mislukken als het commando dat u zoekt is gedefinieerd als een alias.


236
2017-11-05 14:33



Ik ben het eens met lhunath om het gebruik van te ontmoedigen which, en zijn oplossing is volkomen geldig voor BASH-gebruikers. Om draaglijker te zijn, command -v zal in plaats daarvan worden gebruikt:

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

Opdracht command voldoet aan POSIX, kijk hier voor de specificatie: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/command.html

Notitie: type is POSIX-compatibel, maar type -P is niet.


190
2018-01-24 18:16



Ik heb een functie gedefinieerd in mijn .bashrc die dit gemakkelijker maakt.

command_exists () {
    type "$1" &> /dev/null ;
}

Hier is een voorbeeld van hoe het wordt gebruikt (van mijn .bash_profile.)

if command_exists mvim ; then
    export VISUAL="mvim --nofork"
fi

81
2017-10-14 09:24



Het hangt ervan af of u wilt weten of het bestaat in een van de mappen in de $PATH variabele of dat u de absolute locatie ervan kent. Als je wilt weten of het in de $PATH variabele, gebruik

if which programname >/dev/null; then
    echo exists
else
    echo does not exist
fi

anders gebruik

if [ -x /path/to/programname ]; then
    echo exists
else
    echo does not exist
fi

De doorverwijzing naar /dev/null/ in het eerste voorbeeld onderdrukt de uitvoer van de which programma.


66
2018-02-26 22:01



Uitbreiding op de antwoorden van @ lhunath en @ GregV, hier is de code voor de mensen die deze controle gemakkelijk in een if uitspraak:

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

Hier is hoe het te gebruiken:

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

27
2017-12-07 21:17



Probeer het gebruik van:

test -x filename

of

[ -x filename ]

Van de bash manpage onder Voorwaardelijke uitdrukkingen:

 -x file
          True if file exists and is executable.

19
2018-02-26 21:57



Gebruiken hash, als @lhunath suggereert, in een bash-script:

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

Dit script wordt uitgevoerd hash en controleert vervolgens of de afsluitcode van de meest recente opdracht, de waarde die is opgeslagen in $?, is gelijk aan 1. Als hash vindt het niet foo, de exit-code zal zijn 1. Als foo is aanwezig, de exit-code zal zijn 0.

&> /dev/null stuurt standaardfout en standaarduitvoer om van hash zodat het niet op het scherm verschijnt en echo >&2 schrijft het bericht naar standaardfout.


16
2018-06-24 17:01



Ik heb nooit de bovenstaande oplossingen laten werken op de doos waar ik toegang tot heb. Ten eerste is type geïnstalleerd (doen wat meer doet). Dus de ingebouwde richtlijn is nodig. Deze opdracht werkt voor mij:

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

7
2017-07-11 18:38



Als je controleert of het programma bestaat, ga je het waarschijnlijk toch later gebruiken. Waarom probeert u het niet in de eerste plaats?

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

Het is een meer betrouwbare controle dat het programma wordt uitgevoerd dan alleen kijken naar PATH-mappen en bestandsrechten.

Bovendien kunt u een nuttig resultaat van uw programma krijgen, zoals de versie ervan.

Natuurlijk zijn de nadelen dat sommige programma's zwaar kunnen zijn om te starten en sommige geen --version optie om onmiddellijk (en met succes) af te sluiten.


7
2017-07-08 15:14