Come posso verificare se esiste un programma da uno script Bash?


2212

Come verificherei l'esistenza di un programma, in modo da restituire un errore e uscire o continuare con lo script?

Sembra che dovrebbe essere facile, ma mi ha stordito.


Che cos'è un "programma"? Include funzioni e alias? whichritorna vero per questi. typesenza argomenti restituirà inoltre true per le parole riservate e i builtin della shell. Se "programma" significa "eseguibile $PATH", vedere questa risposta .
Tom Hale,

Risposte:


3056

Risposta

POSIX compatibile:

command -v <the_command>

Per ambienti specifici di Bash:

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

Spiegazione

Evitare which. Non solo è un processo esterno si stai lanciando per fare molto poco (builtins significato piace hash, typeo commandsono il modo più economico), si può anche fare affidamento sui comandi incorporati effettivamente fare quello che vuoi, mentre gli effetti di comandi esterni possono facilmente variare da da sistema a sistema.

Perché preoccuparsene?

  • Molti sistemi operativi hanno uno whichche non imposta nemmeno uno stato di uscita , il che significa if which fooche non funzionerà nemmeno lì e segnalerà sempre che fooesiste, anche se non lo fa (si noti che alcune shell POSIX sembrano farlo hashanche per questo ).
  • Molti sistemi operativi fanno whichcose personalizzate e malvagie come cambiare l'output o persino agganciarsi al gestore dei pacchetti.

Quindi, non usare which. Invece usa uno di questi:

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

(Nota a margine minore: alcuni suggeriranno che 2>&-è lo stesso 2>/dev/nullma più breve - questo non è vero . 2>&-Chiude FD 2 che causa un errore nel programma quando tenta di scrivere su stderr, che è molto diverso dal scrivere con successo su di esso e scartare l'output (e pericoloso!))

Se il tuo hash bang è /bin/shallora dovresti preoccuparti di ciò che dice POSIX. typee hashi codici di uscita non sono terribilmente ben definiti da POSIX, ed hashè visto per uscire con successo quando il comando non esiste (non l'ho ancora visto type). commandLo stato di uscita è ben definito da POSIX, quindi è probabilmente il più sicuro da usare.

Se lo script utilizza bash, tuttavia, le regole POSIX non contano più ed entrambe typee hashdiventano perfettamente sicure da usare. typeora ha una -Pricerca solo PATHe hashha l'effetto collaterale che la posizione del comando sarà sottoposta a hash (per una ricerca più veloce la prossima volta che la usi), che di solito è una buona cosa poiché probabilmente verifichi la sua esistenza per usarla effettivamente .

Come semplice esempio, ecco una funzione che viene eseguita gdatese esiste, altrimenti date:

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

35
@Geert: la parte &> / dev / null nasconde il messaggio 'type' emette quando 'foo' non esiste. > & 2 sull'eco assicura di inviare il messaggio di errore all'errore standard anziché all'output standard; perché è una convenzione. Entrambi appaiono sul terminale, ma l'errore standard è sicuramente l'output preferito per messaggi di errore e avvisi imprevisti.
lhunath,

5
il flag -P non funziona in 'sh', ad esempio, stackoverflow.com/questions/2608688/...
momeara

130
Per coloro che non hanno familiarità con il reindirizzamento i / o "avanzato" in bash: 1) 2>&- ("chiudi il descrittore di file di output 2", che è stderr) ha lo stesso risultato di 2> /dev/null; 2) >&2è una scorciatoia per 1>&2, che potresti riconoscere come "reindirizzare stdout a stderr". Consulta la pagina di reindirizzamento i / o della Guida avanzata agli script Bash per ulteriori informazioni.
mikewaters,

9
@mikewaters L'ABS sembra abbastanza avanzato e descrive una vasta gamma di funzionalità CLI bash e non bash, ma è molto negligente sotto molti aspetti e non segue le buone pratiche. Non ho abbastanza spazio in questo commento per scrivere un articolo; ma posso incollare alcuni esempi casuali di codice BAD: while read element ; do .. done <<< $(echo ${ArrayVar[*]}), for word in $(fgrep -l $ORIGINAL *.txt), ls -l "$directory" | sed 1d , {{for a in seq $BEGIN $END}}, ... Molti hanno tentato di contattare gli autori e proporre miglioramenti ma non è un wiki e le richieste sono sbarcati nel vuoto.
lhunath,

56
@mikewaters non2>&- è lo stesso di . Il primo chiude il descrittore di file, mentre il secondo lo reindirizza semplicemente a . Potresti non visualizzare un errore perché il programma tenta di informarti su stderr che stderr è chiuso. 2>/dev/null/dev/null
nyuszika7h,

577

Di seguito è riportato un modo portatile per verificare se esiste un comando $PATH ed è eseguibile:

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

Esempio:

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

Il controllo eseguibile è necessario perché bash restituisce un file non eseguibile se non viene trovato alcun file eseguibile con quel nome $PATH.

Si noti inoltre che se in precedenza esiste un file non eseguibile con lo stesso nome dell'eseguibile $PATH, trattino restituisce il primo, anche se quest'ultimo verrà eseguito. Questo è un bug e viola lo standard POSIX. [ Segnalazione bug ] [ Standard ]

Inoltre, ciò fallirà se il comando che stai cercando è stato definito come alias.


4
Produrrà command -vun percorso anche per un file non eseguibile? Cioè, la -x è davvero necessaria?
einpoklum,

5
@einpoklum -xverifica che il file sia eseguibile, qual è la domanda.
Ken Sharp,

3
@KenSharp: Ma sembra ridondante, dal momento che commandmetterà alla prova se stesso eseguibile - non è vero?
einpoklum,

13
@einpoklum Sì, è necessario. In effetti, anche questa soluzione potrebbe rompersi in un caso limite. Grazie per avermelo fatto notare. dash, bash e zsh saltano tutti i file non eseguibili $PATHdurante l'esecuzione di un comando. Tuttavia, il comportamento di command -vè molto incoerente. Nel trattino, restituisce il primo file corrispondente $PATH, indipendentemente dal fatto che sia eseguibile o meno. In bash, restituisce la prima corrispondenza eseguibile $PATH, ma se non ce ne sono, può restituire un file non eseguibile. E in zsh, non restituirà mai un file non eseguibile.
nyuszika7h,

5
Per quanto ne so, dashè l'unico su quei tre che non è conforme a POSIX; [ -x "$(command -v COMMANDNAME)"]funzionerà negli altri due. Sembra che questo errore sia già stato segnalato ma non abbia ancora ricevuto risposta: bugs.debian.org/cgi-bin/bugreport.cgi?bug=874264
nyuszika7h

210

Concordo con lhunath per scoraggiare l'uso whiche la sua soluzione è perfettamente valida per gli utenti di Bash . Tuttavia, per essere più portatile, command -vdeve essere utilizzato invece:

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

Il comando commandè conforme a POSIX. Vedi qui per le sue specifiche: comando - esegue un comando semplice

Nota: typeè conforme POSIX, ma type -Pnon lo è.


3
Come sopra: exit 1;uccide un xterm, se invocato da lì.
utente sconosciuto

1
Questo non funzionerebbe su uno sh standard: tu e>> non siete istruzioni di reindirizzamento valide.
jyavenard

7
@jyavenard: la domanda è taggata bash , quindi la notazione di reindirizzamento specifica concisa più concisa &>/dev/null. Tuttavia, sono d'accordo con te, ciò che conta davvero è la portabilità, ho modificato la mia risposta di conseguenza, ora usando il reindirizzamento sh standard >/dev/null 2>&1.
GregV

per migliorare ancora di più questa risposta, farei due cose: 1: usa "&>" per semplificarla, come la risposta di Josh. 2: spezzare il {} in una riga aggiuntiva, mettendo una linguetta prima dell'eco, per leggibilità
knocte

Ho appena messo questo liner in una funzione bash se qualcuno lo vuole ... github.com/equant/my_bash_tools/blob/master/tarp.bash
equivalente

94

Ho una funzione definita nel mio .bashrc che rende tutto più semplice.

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

Ecco un esempio di come viene utilizzato (dal mio .bash_profile.)

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

Che cosa &>fa?
Saad Malik,


&>potrebbe non essere disponibile nella tua versione di Bash. Il codice di Marcello dovrebbe funzionare bene; fa la stessa cosa.
Josh Strater,

3
Errore nei builtin e nelle parole riservate: prova thenad esempio con la parola . Vedi questa risposta se richiedi l'esistenza del file eseguibile $PATH.
Tom Hale,

84

Dipende se vuoi sapere se esiste in una delle directory nella $PATHvariabile o se conosci la sua posizione assoluta. Se vuoi sapere se è nella $PATHvariabile, usa

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

altrimenti usa

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

Il reindirizzamento /dev/null/nel primo esempio elimina l'output del whichprogramma.


22
Non dovresti davvero usare "quale" per i motivi delineati nel mio commento.
lhunath,

39

Espandendo le risposte di @lhunath e @ GregV, ecco il codice per le persone che vogliono inserire facilmente quel controllo all'interno di una ifdichiarazione:

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

Ecco come usarlo:

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

13
La volontà di imparare e migliorare deve essere premiata. +1 Questo è pulito e semplice. L'unica cosa che posso aggiungere è che ha commandsuccesso anche per gli alias, che potrebbe essere in qualche modo controintuitivo. Il controllo dell'esistenza in una shell interattiva darà risultati diversi da quando lo si sposta in uno script.
Palec,

1
Ho appena testato e usando shopt -u expand_aliasesignora / nasconde gli alias (come quello alias ls='ls -F'menzionato in un'altra risposta) e shopt -s expand_aliasesli risolve tramite command -v. Quindi forse dovrebbe essere impostato prima del controllo e non impostato dopo, anche se potrebbe influire sul valore di ritorno della funzione se non si acquisisce e restituisce l'output della chiamata di comando in modo esplicito.
dragon788,


16

Per usare hash, come suggerisce @lhunath , in uno script Bash:

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

Questo script viene eseguito hashe quindi controlla se il codice di uscita del comando più recente, il valore archiviato $?, è uguale a 1. In caso hashcontrario foo, il codice di uscita sarà 1. Se foopresente, il codice di uscita sarà 0.

&> /dev/nullreindirizza l'errore standard e l'output standard in hashmodo che non appaia sullo schermo e echo >&2scriva il messaggio nell'errore standard.


8
Perché non solo if hash foo &> /dev/null; then ...?
Beni Cherniavsky-Paskin,

9

Non ho mai avuto le risposte precedenti per lavorare sulla casella a cui ho accesso. Per uno, typeè stato installato (facendo quello che morefa). Quindi è necessaria la direttiva integrata. Questo comando funziona per me:

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

3
Le parentesi non fanno parte della ifsintassi, basta usare if builtin type -p vim; then .... E i backtick sono sintassi molto antiche e deprecate, $()sono supportati anche da shtutti i sistemi moderni.
nyuszika7h,

9

Verificare la presenza di più dipendenze e informare lo stato degli utenti finali

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

Uscita campione:

latex     OK
pandoc    missing

Regolare la 10lunghezza massima del comando. Non è automatico, perché non vedo un modo POSIX non dettagliato per farlo: come posso allineare le colonne di una tabella separata dallo spazio in Bash?

Controllare se alcuni aptpacchetti sono installati con dpkg -se installarli altrimenti .

Vedi: Controlla se è installato un pacchetto apt-get e installalo se non è su Linux

È stato precedentemente menzionato in: Come posso verificare se esiste un programma da uno script Bash?


1
Modo non dettagliato per farlo: 1) sbarazzarsi dell'identificatore di larghezza; 2) aggiungi uno spazio dopo la stampa del nome del tuo comando; 3) reindirizza il tuo ciclo for a column -t(parte di util-linux).
Patrice Levesque,

8

Se controlli l'esistenza del programma, probabilmente lo eseguirai in seguito comunque. Perché non provare a eseguirlo in primo luogo?

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

È un controllo più affidabile che il programma viene eseguito piuttosto che guardare semplicemente le directory PATH e le autorizzazioni dei file.

Inoltre puoi ottenere alcuni risultati utili dal tuo programma, come la sua versione.

Naturalmente gli svantaggi sono che alcuni programmi possono essere pesanti da avviare e alcuni non hanno --versionun'opzione per uscire immediatamente (e con successo).


6

hash foo 2>/dev/null: funziona con Z shell (Zsh), Bash, Dash e Ash .

type -p foo: sembra funzionare con Z shell, Bash e ash ( BusyBox ), ma non Dash (interpreta -pcome argomento).

command -v foo: funziona con Z shell, Bash, Dash, ma non ash (BusyBox) ( -ash: command: not found).

Si noti inoltre che builtinnon è disponibile con ash e Dash.


4

Usa i built-in di Bash se puoi:

which programname

...

type -P programname

15
Eh? whichnon è incorporato in Bash.
Tripleee,

digitare -P nome programma deve essere preferito, vedere risposta accettata
RobertG

@RobertG Tutto quello che vedo è che -Pnon è POSIX. Perché è type -Ppreferito?
mikemaccana,

Avrei dovuto dire che "essere preferito negli ambienti bash" - mentre mi proponevo di rispondere al commento precedente specifico di bash. Comunque, è stato anni fa - suppongo che dovrei, ancora una volta,
indicarti

4

Il comando -vfunziona correttamente se l'opzione POSIX_BUILTINS è impostata per<command> test per, ma può non riuscire in caso contrario. (Ha funzionato per me per anni, ma di recente mi sono imbattuto in uno in cui non ha funzionato.)

Trovo che quanto segue sia più a prova di errore:

test -x $(which <command>)

Dal momento che verifica tre cose: percorso, esistenza e permesso di esecuzione.


Non funziona test -x $(which ls)restituisce 0, come fa test -x $(which sudo), anche se lsè installato e eseguibile e sudonon è nemmeno installato nel contenitore docker in cui sto eseguendo.
algal

@algal Devi usare le virgolette credo, quinditest -x "$(which <command>)"
JoniVR

@algal Forse lsè aliasato ? Non penso che funzionerebbe se il comando avesse un parametro.
AnthonyC,

3

Per gli interessati, nessuna delle metodologie nelle risposte precedenti funziona se si desidera rilevare una libreria installata. Immagino che ti rimanga con il controllo fisico del percorso (potenzialmente per i file di intestazione e simili), o qualcosa del genere (se sei su una distribuzione basata su Debian):

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

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

Come puoi vedere da quanto sopra, una risposta "0" dalla query indica che il pacchetto non è installato. Questa è una funzione di "grep" - uno "0" significa che è stata trovata una corrispondenza, un "1" significa che non è stata trovata alcuna corrispondenza.


10
Tuttavia, l'anti-pattern cmd; if [ $? -eq 0 ]; thendovrebbe essere refactored aif cmd; then
tripleee

Funziona solo con le librerie installate tramite dpkgoapt
Weijun Zhou

3

Ci sono un sacco di opzioni qui, ma sono rimasto sorpreso senza una battuta veloce. Questo è quello che ho usato all'inizio dei miei script:

[[ "$(command -v mvn)" ]] || { echo "mvn is not installed" 1>&2 ; exit 1; }
[[ "$(command -v java)" ]] || { echo "java is not installed" 1>&2 ; exit 1; }

Questo si basa sulla risposta selezionata qui e su un'altra fonte.


2

Direi che non esiste alcun modo portatile e affidabile al 100% a causa di penzoloni alias. Per esempio:

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

Certo, solo l'ultimo è problematico (senza offesa per Ringo!). Ma tutti sono validi aliasdal punto di vista di command -v.

Per respingere quelli penzolanti come ringo, dobbiamo analizzare l'output del aliascomando integrato della shell e ricorrere in essi ( command -vnon è un superiore a aliasqui.) Non esiste alcuna soluzione portatile per esso, e nemmeno un Bash- la soluzione specifica è piuttosto noiosa.

Si noti che una soluzione come questa rifiuterà incondizionatamente alias ls='ls -F':

test() { command -v $1 | grep -qv alias }

Buon punto. Tuttavia, quando eseguito all'interno di uno script bash, gli alias non sono visibili.
Basil Musa,

1
C'è anche un problema, restituirà false quando il comando 'alias' è selezionato. Quando dovrebbe tornare vero. Esempio: test "alias"
Basil Musa

2
Ho appena testato e usando shopt -u expand_aliasesignora / nasconde questi alias e shopt -s expand_aliasesli mostra tramite command -v.
dragon788,

2

Questo dirà in base alla posizione se il programma esiste o no:

    if [ -x /usr/bin/yum ]; then
        echo "This is Centos"
    fi

Sì, ho aggiunto questo comando se è necessario installare un pacchetto in sevrer, Open suse, centos, Debian
Klevin Kona,

L'evidenziazione della sintassi è disattivata nella riga "echo". Qual'è la soluzione? Suggerisce che lo script Bash dovrebbe essere diverso?
Peter Mortensen,

@PeterMortensen L'evidenziazione della sintassi è disattivata perché non riconosce che è una stringa.
Adrien,

1

Il whichcomando potrebbe essere utile.uomo che

Restituisce 0 se viene trovato l'eseguibile e restituisce 1 se non viene trovato o non eseguibile:

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 executable

       2      if an invalid option is specified

La cosa bella whichè che capisce se l'eseguibile è disponibile nell'ambiente in cui whichviene eseguito - salva alcuni problemi ...


Usa quale se stai cercando un eseguibile chiamato pippo, ma vedi la mia risposta se vuoi controllare un particolare file / percorso / a / a / nome / pippo. Nota anche che potrebbe non essere disponibile su alcuni sistemi minimi, anche se dovrebbe essere presente su qualsiasi installazione completa ...
dmckee --- ex-moderatore gattino

9
Non fare affidamento sullo stato di uscita di cui. Molti sistemi operativi hanno un valore che non imposta nemmeno uno stato di uscita diverso da 0.
lhunath

1

La mia configurazione per un Debian server :

Ho avuto il problema quando più pacchetti contenevano lo stesso nome.

Per esempio apache2. Quindi questa era la mia soluzione:

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

Se voi / ragazze non riuscite a far funzionare le cose nelle risposte qui e vi state strappando i capelli dalla schiena, provate a eseguire lo stesso comando usando bash -c . Guarda questo delirio sonnambulo. Questo è ciò che accade realmente quando si esegue $ (comando secondario):

Primo. Può darti un output completamente diverso.

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

Secondo. Non può darti alcun risultato.

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

Le differenze sono causate dalla differenza tra la modalità interattiva e non interattiva della shell. ~ / .Bashrc viene letto solo quando la shell non è di accesso e interattiva. Il secondo sembra strano, perché questo deve essere causato da una differenza nella variabile d'ambiente PATH, ma i subshells ereditano l'ambiente.
Palec,

Nel mio caso .bashrcho [ -z "$PS1" ] && returnanteposto # If not running interactively, don't do anythingquindi immagino che sia una ragione per cui anche l'approvvigionamento esplicito di bashrc in modalità non interattiva non aiuta. Il problema può essere risolto chiamando uno script con un operatore punto ss64.com/bash/source.html , . ./script.shma non è una cosa che vorresti ricordare di digitare ogni volta.
user619271,

1
Gli script di sourcing che non dovrebbero essere forniti sono una cattiva idea. Tutto quello che stavo cercando di dire è che la tua risposta ha poco a che fare con la domanda posta e molto a che fare con Bash e la sua modalità (non) interattiva.
Palec,

Se spiegasse cosa sta succedendo in questi casi, sarebbe un'utile aggiunta a una risposta.
Palec,

0

La variante hash ha una trappola: nella riga di comando è possibile ad esempio digitare

one_folder/process

per eseguire il processo. Per questo la cartella principale di one_folder deve essere in $ PATH . Ma quando provi a eseguire l'hashing di questo comando, riuscirà sempre:

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

4
"Per questo la cartella principale di one_folder deve essere in $PATH" - Questo è completamente inaccurato. Provalo. Perché ciò funzioni, one_folder deve trovarsi nella directory corrente .
Wildcard

0

In secondo luogo l'uso di "comando -v". Ad esempio in questo modo:

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

0

Ho dovuto verificare se Git era installato come parte della distribuzione del nostro server CI . Il mio script finale di Bash era il seguente (server Ubuntu):

if ! builtin type -p git &>/dev/null; then
  sudo apt-get -y install git-core
fi

3
Il condizionale è piuttosto inutile, modulo il tempo di avvio per eseguire apt-get, poiché apt-get sarà soddisfatto e uscirà se git-core è già installato.
Tripleee

3
Il suo tempo di avvio non è trascurabile, ma la motivazione più importante è sudo: senza il condizionale, si fermerebbe sempre e chiederebbe la password (a meno che non abbia fatto un sudo di recente). A proposito, può essere utile farlo in sudo -p "Type your password to install missing git-core: "modo che il prompt non venga fuori dal nulla.
Beni Cherniavsky-Paskin,

0

Per imitare Bash type -P cmd, possiamo usare il POSIX conforme env -i type cmd 1>/dev/null 2>&1.

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>&1 || { echo "$cmd not found"; exit 1; }

7
Perché questo è stato votato? Su quali sistemi funziona davvero per te? typesembra essere un builtinnella maggior parte delle shell, quindi questo non può funzionare perché envusa execvpper essere eseguito, commandquindi commandnon può essere un builtin(e builtinverrà sempre eseguito nello stesso ambiente). Questo non per me in bash, ksh93, zsh, busybox [a]she dashognuno dei quali forniscono typecome un builtin di shell.
Adrian Frühwirth,

0

Se non è typedisponibile alcun comando esterno (come dato scontato qui ), possiamo utilizzare POSIX conforme 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

Almeno su Mac OS X v10.6.8 (Snow Leopard) utilizzando Bash 4.2.24 (2) command -v lsnon corrisponde a uno spostamento /bin/ls-temp.


0

Nel caso in cui si desideri verificare se esiste un programma ed è davvero un programma, non un comando incorporato di Bash , quindi command, typee hashnon sono appropriati per il test in quanto restituiscono tutti 0 stato di uscita per i comandi integrati.

Ad esempio, esiste il programma orario che offre più funzioni rispetto al comando incorporato time . Per verificare se il programma esiste, suggerirei di utilizzare whichcome nell'esempio seguente:

# 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

0

Volevo che rispondesse alla stessa domanda ma che fosse eseguita in un Makefile.

install:
    @if [[ ! -x "$(shell command -v ghead)" ]]; then \
        echo 'ghead does not exist. Please install it.'; \
        exit -1; \
    fi

-1

copione

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

Risultato

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

-1

Lo uso perché è molto semplice:

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

o

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

Utilizza lo stato dell'eco dei programmi incorporati della shell e dell'output standard e nulla per l'errore standard. D'altra parte, se non viene trovato un comando, viene visualizzato lo stato solo l'errore standard.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.