Kako provjeriti postoji li program iz bash skripte?

Kako mogu provjeriti postoji li program koji će ili vratiti pogrešku i izaći, ili nastaviti koristiti skriptu?

Čini se da bi to trebalo biti lako, ali me je udaralo.

1748
27 февр. set gregh 27 feb . 2009-02-27 00:52 '09 u 12:52 2009-02-27 00:52
@ 35 odgovora
  • 1
  • 2

Odgovor

POSIX kompatibilnost:

 command -v <the_command> 

Za okruženja bash :

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

opis

Izbjegavajte which . Ne samo da je to vanjski proces koji se izvodi vrlo malo (to znači da su ugrađene funkcije poput hash , type ili command mnogo jeftinije), možete se osloniti i na ugrađene funkcije kako biste zapravo radili ono što želite. dok se učinci vanjskih naredbi mogu lako razlikovati od sustava do sustava.

Zašto brinuti?

  • Mnogi operacijski sustavi imaju which što čak ne postavlja izlazni status , što znači da if which foo ne radi tamo i uvijek će biti da foo postoji, čak i ako nije (napominjemo da neke POSIX ljuske također izgledaju kao da rade) ovo je za hash ).
  • Mnogi operativni sustavi čine jednostavne i zle, poput promjene izlaza ili čak povezivanja s upraviteljem paketa.

Zato nemojte koristiti which . Umjesto toga upotrijebite jedno od sljedećeg:

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

(Manja strana napomene: neki pretpostavljaju da je 2>> ista 2>/dev/null , ali kraća je pogreška. što je vrlo različito od uspješnog pisanja i odbacivanja izlaza (i opasno!))

Ako je vaša hash track /bin/sh , onda trebate voditi računa o tome što kaže POSIX. type i hash izlazni kodovi nisu dobro definirani POSIX-om, a hash , kao što možete vidjeti, uspješno završava kada naredba ne postoji (još se nije vidjela s type ). command izlaza command je dobro definiran POSIX-om, tako da je vjerojatno najsigurniji za korištenje.

Ako vaša skripta koristi bash , iako POSIX pravila više nisu važna, a oba type i hash postaju potpuno sigurni za korištenje. type sada ima -P za pretraživanje samo PATH , a hash ima nuspojavu da će se lokacija naredbe raspršiti (za brže pretraživanje sljedećeg puta kada je koristite), što je obično dobro, jer vjerojatno provjerite njegovo postojanje tako da zapravo ga koristiti.

Kao jednostavan primjer, ovdje je funkcija koja pokreće gdate ako postoji, inače je date :

 gnudate() { if hash gdate 2>/dev/null; then gdate "$@" else date "$@" fi } 
2478
24 марта '09 в 15:45 2009-03-24 15:45 Odgovor je dao lhunath 24. ožujka u 15:45 2009-03-24 15:45

Slijedi prijenosni način za provjeru postoji li naredba u $PATH i je li izvršna:

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

primjer:

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

Provjera je potrebna jer bash vraća ne-izvršnu datoteku ako nema izvršne datoteke s ovim imenom u $PATH .

Također imajte na umu da ako nekorištena datoteka s istim imenom kao izvršna datoteka postoji ranije u $PATH , crtica vraća prvu, iako će ona biti izvršena. Ova pogreška krši POSIX standard. [ Izvješće o pogrešci ] [ Standard ]

Osim toga, to neće uspjeti ako je tim koji tražite označen kao nadimak.

324
05 нояб. odgovor je dan nyuszika7h 05 Nov. 2014-11-05 17:33 '14 u 17:33 2014-11-05 17:33

Slažem se s lhunathom da obeshrabri korištenje which i njegovo rješenje je izvrsno za korisnike BASH-a. Međutim, da biste bili prenosivi, umjesto toga koristite command -v :

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

command kompatibilna je s POSIX-om, pogledajte ovdje za njegovu specifikaciju: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/command.html

Napomena: type kompatibilan s POSIX-om, ali type -P nije.

194
24 янв. odgovor je dao GregV Jan 24 2011-01-24 21:16 '11 u 21:16 2011-01-24 21:16

Imam funkciju definiranu u mom .bashrc, koja olakšava rad.

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

Evo primjera kako je korišten (s mog .bash_profile .)

 if command_exists mvim ; then export VISUAL="mvim --nofork" fi 
83
14 окт. odgovor dao Josh Strater 14. listopada 2010-10-14 12:24 '10 u 12:24 2010-10-14 12:24

To ovisi o tome želite li znati postoji li u jednom od direktorija u $PATH varijabli ili znate li njegovu apsolutnu lokaciju. Ako želite znati je li u $PATH varijabli, koristite

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

inače koristiti

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

Preusmjeravanje na /dev/null/ u prvom primjeru potiskuje izlaz tog programa.

68
27 февр. Odgovor je dao dreamlax 27. veljače. 2009-02-27 01:01 '09 u 1:01 2009-02-27 01:01

Uključujući odgovore @lhunath i @GregV, ovdje je kôd za osobe koje žele lako izvršiti ovu provjeru unutar if :

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

Evo kako ga koristiti:

 if exists bash; then echo 'Bash exists!' else echo 'Your system does not have Bash' fi 
30
08 дек. odgovor od Romário 08 prosinca. 2015-12-08 00:17 '15 u 0:17 2015-12-08 00:17

Pokušajte upotrijebiti:

 test -x filename 

ili

 [ -x filename ] 

Na bash man stranici Uvjetni izrazi :

  -x file True if file exists and is executable. 
20
27 февр. odgovor je dmckee 27. veljače 2009-02-27 00:57 '09 u 0:57 2009-02-27 00:57

Za korištenje hash , kao što to sugerira @lhunath , u bash skripti:

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

Ova skripta pokreće hash a zatim provjerava je li izlazni kod najnovije naredbe vrijednost pohranjena u $? , jednako 1 . Ako hash ne pronađe foo , izlazni kod je 1 . Ako foo prisutan foo , izlazni kod je 0 .

/dev/null preusmjerava standardnu ​​pogrešku i standardni izlaz iz hash tako da se ne pojavljuje na zaslonu, a echo >> piše poruku na standardnu ​​pogrešku.

15
24 июня '11 в 20:01 2011-06-24 20:01 odgovor je dcharles 24. lipnja '11 u 20:01 2011-06-24 20:01

Nikada nisam primio gore navedena rješenja za rad s kutijom u koju imam pristup. Primjerice, postavljen je tip (koji radi više). Stoga je potrebna ugrađena direktiva. Ovaj tim radi za mene:

 if [ `builtin type -p vim` ]; then echo "TRUE"; else echo "FALSE"; fi 
8
11 июля '09 в 21:38 2009-07-11 21:38 odgovor je dao Magnus 11. srpnja u 21:38 2009-07-11 21:38

Potražite više zavisnosti i prijavite status krajnjim korisnicima.

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

Primjer izlaza:

 latex OK pandoc missing 

Podesite 10 na maksimalnu duljinu naredbe. Nije automatsko, jer ne vidim način rada POSIX-a koji nije složen: kako poravnati stupce tablice odvojene razmakom u Bashu?

7
23 марта '14 в 13:09 2014-03-23 13:09 odgovor od Ciro Santilli 23 改造 中心 六四 事件 法轮功 23. ožujka '14. u 13:09 2014-03-23 ​​13:09

Ako provjerite postojanje programa, vjerojatno ćete ga kasnije pokrenuti. Zašto prvo ne pokušate pokrenuti?

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

Ovo je pouzdanija provjera da program radi, a ne samo pregledavanje PATH direktorija i dozvola za datoteke.

Osim toga, možete dobiti koristan rezultat iz vašeg programa, na primjer, njegova verzija.

Naravno, nedostaci su u tome što se neki programi teško pokreću, a neki nemaju --version opciju za trenutačan (i uspješan) izlaz.

7
08 июля '13 в 18:14 2013-07-08 18:14 odgovor je dat 0xF 08. srpnja u 18:14 2013-07-08 18:14

hash foo 2>/dev/null : radi s zsh, bash, crtama i pepelom.

type -p foo : radi s zsh, bash i ash (busybox), ali ne i crtom (interpretira -p kao argument).

command -v foo : radi s zsh, bash, dash, ali ne i pepeo (busybox) ( -ash: command: not found ).

Također imajte na umu da builtin nije dostupan s ash i dash .

6
21 июля '14 в 3:13 2014-07-21 03:13 odgovor je dan blueyed 21. srpnja 14. u 3:13 2014-07-21 03:13

Zašto ne biste koristili ugrađene značajke Basha ako možete?

 which programname 

...

 type -P programname 
6
24 марта '09 в 14:23 2009-03-24 14:23 odgovor je dan bin 24. ožujka 2009. u 14:23 2009-03-24 14:23

Za one koji su zainteresirani, nijedna od gore navedenih metodologija ne funkcionira ako želite otkriti instaliranu knjižnicu. Pretpostavljam da morate samo fizički provjeriti put (možda za datoteke zaglavlja, itd.) Ili nešto slično (ako koristite distribuciju temeljenu na Debianu):

 dpkg --status libdb-dev | grep -q not-installed if [ $? -eq 0 ]; then apt-get install libdb-dev fi 

Kao što se može vidjeti iz gore navedenog, odgovor "0" iz zahtjeva znači da paket nije instaliran. Ova funkcija "grep" - "0" znači podudaranje, "1" znači da nije pronađeno nijedno podudaranje.

4
16 янв. Odgovor daje Nathan Crause 16. siječnja 2010-01-16 02:16 '10 u 2:16 2010-01-16 02:16

which naredba može biti korisna. čovjek koji

Vraća 0 ako je izvršna datoteka pronađena, 1 ako nije pronađena ili nije izvršna:

 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 

Dobra stvar je da otkrije je li izvršna datoteka dostupna u okruženju u kojem se izvodi - štedi nekoliko problema ...

-Adam

3
27 февр. odgovor je dao David Davis 27. veljače. 2009-02-27 00:56 '09 u 0:56 2009-02-27 00:56

Rekao bih da nema prijenosnog i 100% pouzdanog načina zbog vješanja alias . Na primjer:

 alias john='ls --color' alias paul='george -F' alias george='ls -h' alias ringo=/ 

Naravno, samo je potonje problematično (bez uvrede Ringu!), Ali svi oni su valjani alias u smislu command -v .

Da bi odbacili nečistu, kao što je ringo , trebamo analizirati izlazni alias ugrađene naredbe i rekurzirati u ljusku ( command -v alias ne prelazi alias ). Ne postoji prijenosno rješenje za to, pa čak i Bash-specifično rješenje je prilično zamorno.

Napominjemo da ovo rješenje bezuvjetno odbija alias ls='ls -F'

 test() { command -v $1 | grep -qv alias } 
3
10 марта '16 в 5:31 2016-03-10 05:31 je dao odgovor nodakai 10. ožujka u 5:31 sati 2016-03-10 05:31

Ako naredba vanjskog type nije dostupna (kao što je ovdje uobičajeno), možemo koristiti POSIX-kompatibilan env -i sh -c 'type cmd 1>/dev/null 2>> :

 # portable version of Bash type -P cmd (without output on stdout) typep() { command -p env -i PATH="$PATH" sh -c ' export LC_ALL=C > 

Barem na Mac OS X 10.6.8 pomoću command -v ls Bash 4.2.24 (2) command -v ls se ne podudara s premještenom /bin/ls-temp .

2
20 нояб. odgovor je dao freno 20. studenog 2014-11-20 19:55 '14 u 19:55 2014-11-20 19:55

Ovdje ima mnogo opcija, ali nisam bio iznenađen kada nije bilo brzih znakova od jednog reda, to je ono što sam koristio na početku svojih skripti: [[ "$(command -v mvn)" ]] || { echo "mvn is not installed" 1> exit 1; } [[ "$(command -v java)" ]] || { echo "java is not installed" 1> exit 1; } [[ "$(command -v mvn)" ]] || { echo "mvn is not installed" 1> exit 1; } [[ "$(command -v java)" ]] || { echo "java is not installed" 1> exit 1; } [[ "$(command -v mvn)" ]] || { echo "mvn is not installed" 1> exit 1; } [[ "$(command -v java)" ]] || { echo "java is not installed" 1> exit 1; } [[ "$(command -v mvn)" ]] || { echo "mvn is not installed" 1> exit 1; } [[ "$(command -v java)" ]] || { echo "java is not installed" 1> exit 1; } [[ "$(command -v mvn)" ]] || { echo "mvn is not installed" 1> exit 1; } [[ "$(command -v java)" ]] || { echo "java is not installed" 1> exit 1; }

Ovo se temelji na odabranom odgovoru i drugom izvoru (i malo sam svirala).

Nadam se da će to biti korisno za druge.

1
19 июня '18 в 15:02 2018-06-19 15:02 Odgovor je dao Keisar 19. lipnja 18 u 15:02 2018-06-19 15:02

Ako želite provjeriti postoji li program i je li stvarno program, a ne bash ugrađenu naredbu , tada command , type i hash nisu prikladni za testiranje, jer svi vraćaju 0 izlazni status za ugrađene naredbe.

Na primjer, postoji vremenski program koji nudi više značajki od ugrađenog vremena . Da biste provjerili postoji li program, predlažem da koristite which , kao u sljedećem primjeru:

 # first check if the time program exists timeProg=`which time` if [ "$timeProg" = "" ] then echo "The time program does not exist on this system." exit 1 fi # 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 
1
19 июня '16 в 2:19 2016-06-19 02:19 odgovor je dat rpr 19. lipnja 16 u 2:19 2016-06-19 02:19

Ako ne uspijete učiniti nešto višim / nižim da biste radili i izvukli kosu s leđa, pokušajte izvršiti istu naredbu koristeći bash -c . Pogledajte samo ovu sumnjivu glupost, to je ono što se stvarno događa kada se izvrši $ (pod-naredba):

Prije svega. To vam može dati potpuno drugačiji izlaz.

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

Drugo. Ne može vam dati nikakav zaključak.

 $ command -v nvm nvm $ bash -c "command -v nvm" $ bash -c "nvm --help" bash: nvm: command not found 
1
26 авг. odgovor od strane korisnika619271 26. kolovoza. 2015-08-26 12:23 '15 u 12:23 sati 2015-08-26 12:23

moje postavljanje za debian poslužitelj. Imam problem kada nekoliko paketa sadrži isto ime. na primjer apache2. to je bila moja odluka.

 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 } 
1
27 марта '15 в 17:26 2015-03-27 17:26 odgovor je dat ThCTLo 27. ožujka '15 u 17:26 2015-03-27 17:26

U hash varijanti postoji jedna pogreška: na naredbenom retku možete, na primjer, unijeti

 one_folder/process 

da biste dovršili postupak. Da biste to učinili, nadređena mapa one_folder mora biti u $ PATH. Ali kada pokušate hash ovu naredbu, ona će uvijek biti uspješna:

 hash one_folder/process; echo $? # will always output '0' 
1
14 дек. odgovor se daje anycast.cw 14. prosinca. 2011-12-14 15:41 '11 u 15:41 2011-12-14 15:41

Za emulaciju Bash type -P cmd , možemo koristiti POSIX-kompatibilan env -i type cmd 1>/dev/null 2>> .

 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> || { echo "$cmd not found"; exit 1; } 
1
01 июня '11 в 20:49 2011-06-01 20:49 odgovor je dat tim 01 Jun '11 u 20:49 2011-06-01 20:49

Naredba -v radi dobro ako je POSIX_BUILTINS opcija postavljena za parametar <command> , ali možda neće uspjeti ako nije. (radio je za mene godinama, ali nedavno je došao do mjesta na kojem nije radio).

Smatram sljedeće pouzdanije:

 test -x $(which <command>) 

Budući da provjerava 3 stvari: put, postojanje i dopuštenje za izvođenje.

1
25 июня '18 в 19:53 2018-06-25 19:53 odgovor se daje AnthonyC 25. lipnja 18 u 19:53 2018-06-25 19:53

Izvješće, ovisno o lokaciji, ako program postoji ili ne.

 if [ -x /usr/bin/yum ]; then echo This is Centos fi 
1
27 нояб. Odgovor daje Klevin Kona 27. studenog. 2018-11-27 19:03 '18 u 19:03 2018-11-27 19:03

Drugo, koristite naredbu -v. Na primjer. na primjer:

 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 
1
06 нояб. odgovor daje korisnik2961933 06. studenog. 2013-11-06 22:06 '13 u 10:06 pm 2013-11-06 22:06

Koristim ga jer je vrlo jednostavna:

 if [ `> 

ili

 if [ `> 

Ona koristi shell ugrađeni i softverski echo status za stdout i ništa za stderr s druge strane, ako naredba nije pronađena, ima status echos samo za stderr.

0
22 сент. Odgovor je dat 22. rujna 2015-09-22 03:41 '15 u 03:41 2015-09-22 03:41

skripta

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

Rezultat

 ✘ [ABRT]: notacmd: command does not exist hits command 0 /usr/bin/bash Fin. 
0
06 сент. odgovor je dan ecwpz91 06 sep . 2017-09-06 03:42 '17 u 3:42 2017-09-06 03:42
 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 
-1
16 апр. odgovor Da'Jour dana 16. travnja 2017-04-16 04:21 '17 u 4:21 2017-04-16 04:21

Morao sam provjeriti je li git instaliran kao dio naše implementacije CI poslužitelja. Moja zadnja bash skripta bila je sljedeća (Ubuntu poslužitelj):

 if ! builtin type -p git  then sudo apt-get -y install git-core fi 

Nadam se da ovo pomaže nekom drugom!

-1
08 апр. odgovor dao Greg K 08 travanj. 2011-04-08 18:30 '11 u 18:30 2011-04-08 18:30
  • 1
  • 2

Pogledajte ostala pitanja o oznakama ili Ask a Question