Bir programın Bash betiğinden olup olmadığını nasıl kontrol edebilirim?


2209

Bir programın var olduğunu, bir hata döndürüp çıkacak veya komut dosyasıyla devam edecek şekilde nasıl doğrularım?

Kolay olmalı gibi görünüyor, ama beni çok yoruyor.


"Program" nedir? İşlevler ve takma adlar içeriyor mu? whichbunlar için true değerini döndürür. typebağımsız değişkenler ek olarak ayrılmış sözcükler ve kabuk yerleşikleri için true değerini döndürür. "Program" "içinde excutable" anlamına geliyorsa $PATH, bu cevaba bakınız .
Tom Hale

Yanıtlar:


3052

Cevap

POSIX uyumlu:

command -v <the_command>

Bash'a özgü ortamlar için:

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

açıklama

Kaçının which. Bu sadece (anlam builtins gibi çok az yapıyor kaldın fırlatma harici süreç sensin hash, typeya commandbir yol ucuzdur) dış komutları etkileri kolayca değişebilir ederken, aynı zamanda, aslında ne istediğinizi yapmak yerleşikleri güvenebilirsiniz sistemden sisteme.

Neden önemsiyorsun?

  • Birçok işletim sistemleri var whicholduğunu bile bir çıkış durumunu ayarlamak gelmez , yani if which fooorada bile çalışmaz ve olacak her zaman rapor fooo (bazı POSIX kabukları için yapmasını görünen notu olmasa bile, var olan hashçok).
  • Birçok işletim sistemi which, çıktıyı değiştirmek veya hatta paket yöneticisine bağlanmak gibi özel ve kötü şeyler yapar.

Yani, kullanma which. Bunun yerine aşağıdakilerden birini kullanın:

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

(Küçük yan not: bazıları 2>&-aynı 2>/dev/nullama daha kısa önerecektir - bu yanlıştır . Stderr'e yazmaya çalıştığında programda 2>&-bir hataya neden olan FD 2'yi kapatır , bu da başarılı bir şekilde yazmaktan ve çıktıyı atmaktan çok farklıdır. (ve tehlikeli!))

Eğer karma patlamanız ise /bin/shPOSIX'in söylediklerine dikkat etmelisiniz. typeve hash'nin çıkış kodları POSIX tarafından çok iyi tanımlanmamıştır hashve komut mevcut olmadığında başarılı bir şekilde çıktığı görülür (bunu henüz görmedim type). command'nin çıkış durumu POSIX tarafından iyi tanımlanmıştır, böylece muhtemelen en güvenli olanıdır.

Senaryonuz kullandığı takdirde bashde, POSIX kuralları meselesi artık gerçekten yok ve her iki typeve hashkullanımına tamamen güvenli hale gelir. typeşimdi var -Psadece arama yapmak PATHve hashkomutun konumu muhtemelen aslında amacıyla varlığını kontrol kullandığımızdan genellikle iyi bir şey olduğu, (daha hızlı arama dahaki sefere bunu kullanmak için) karma olacağını yan etkisi yoktur .

Basit bir örnek olarak, gdatevarsa, çalışan bir işlev , aksi takdirde date:

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

35
@Geert: &> / dev / null bölümü, 'foo' olmadığında 'type' mesajını gizler. Yankı üzerindeki> & 2, hata mesajını standart çıktı yerine standart hataya gönderdiğinden emin olur; çünkü bu kongre. Her ikisi de terminalinizde görünür, ancak standart hata kesinlikle hata mesajları ve beklenmeyen uyarılar için tercih edilen çıktıdır.
lhunath

5
-P bayrağı 'sh'
biçiminde çalışmaz

130
Aşina olanlar için 'gelişmiş' I / O yönlendirme parçalamak: 1) 2>&- ( "yakın çıkış dosya tanıtıcısı 2") Stderr olup, aynı sonucu olarak var 2> /dev/null; 2) "stdout'u stderr'a yönlendir" olarak tanıyabileceğiniz >&2bir kısayoldur 1>&2. Daha fazla bilgi için Gelişmiş Bash Komut Dosyası Kılavuzu i / o yeniden yönlendirme sayfasına bakın.
mikewaters

9
@mikewaters ABS oldukça gelişmiş görünüyor ve çok çeşitli bash ve bash olmayan CLI işlevlerini açıklıyor, ancak birçok yönden çok ihmalkar ve iyi uygulamaları takip etmiyor. Bu yorumda yazı yazmak için neredeyse yeterli alanım yok; ama KÖTÜ birkaç kod rastgele örnekler yapıştırabilirsiniz: while read element ; do .. done <<< $(echo ${ArrayVar[*]}), for word in $(fgrep -l $ORIGINAL *.txt), ls -l "$directory" | sed 1d , {{için de seq $BEGIN $END}} ... Birçok yazarlarla iletişim ve iyileştirmeler önermek için çalıştık ama hiçbir wiki olduğunu ve istekleri sağır kulaklara inmiş.
lhunath

56
@mikewaters 2>&-ile aynı değildir2>/dev/null . Birincisi dosya tanımlayıcısını kapatırken ikincisi dosyaya yönlendirir /dev/null. Program size stderr hakkında stderr'ın kapalı olduğunu bildirmeye çalıştığından bir hata göremeyebilirsiniz.
nyuszika7h

575

Aşağıdakiler, bir komutun var olup olmadığını $PATH ve yürütülebilir olup olmadığını kontrol etmenin taşınabilir bir yoludur :

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

Misal:

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

Yürütülebilir denetim gereklidir; çünkü bu adda yürütülebilir bir dosya bulunmazsa bash yürütülebilir olmayan bir dosya döndürür $PATH.

Ayrıca, yürütülebilir dosya ile aynı ada sahip yürütülebilir olmayan bir dosya daha önce varsa $PATH, sonrakinin yürütülmesine rağmen dash'in ilkini döndürdüğünü unutmayın. Bu bir hatadır ve POSIX standardını ihlal etmektedir. [ Hata raporu ] [ Standart ]

Ayrıca, aradığınız komut bir takma ad olarak tanımlanmışsa bu başarısız olur.


4
Will command -vbile olmayan bir yürütülebilir dosya için bir yol üretmek? Yani, -x gerçekten gerekli mi?
einpoklum

5
@einpoklum -xdosyanın yürütülebilir olduğunu sınar, bu da sorunun ne olduğudur .
Ken Sharp

3
@KenSharp: Ama bu gereksiz gibi görünüyor, çünkü commandkendisi çalıştırılabilirliğini test edecek - değil mi?
einpoklum

13
@einpoklum Evet, bu gerekli. Aslında, bu çözüm bile bir kenarda kırılabilir. Bunu dikkatime sunduğunuz için teşekkürler. tire, bash ve zsh $PATHkomutları yürütülürken çalıştırılamayan dosyalar üzerinde atlar . Ancak, davranışı command -vçok tutarsızdır. Kısa çizgi içinde $PATH, çalıştırılabilir olup olmadığına bakılmaksızın, eşleşen ilk dosyayı döndürür . Bash içinde ilk çalıştırılabilir eşleşmeyi döndürür $PATH, ancak hiçbiri yoksa çalıştırılamayan bir dosya döndürebilir. Ve zsh içinde asla çalıştırılamayan bir dosya döndürmez.
nyuszika7h

5
Anlayabildiğim kadarıyla dashPOSIX uyumlu olmayan bu üç taneden sadece biri; [ -x "$(command -v COMMANDNAME)"]diğer ikisinde çalışacak. Görünüşe göre bu hata zaten bildirildi, ancak henüz bir yanıtı yok: bugs.debian.org/cgi-bin/bugreport.cgi?bug=874264
nyuszika7h 26:17

210

Lhunath'ın kullanımını caydırmak için katılıyorum whichve çözümü Bash kullanıcıları için tamamen geçerli . Ancak, daha portatif command -volmak için, bunun yerine kullanılacaktır:

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

Komut commandPOSIX uyumlu. Özellikleri için buraya bakın: komut - basit bir komut yürütme

Not: typePOSIX uyumludur, ancak type -Pdeğildir.


3
Yukarıdaki ile aynı - exit 1;eğer oradan çağrılırsa bir xterm öldürür.
kullanıcı bilinmiyor

1
Bu standart bir sh üzerinde çalışmaz: siz &> geçerli bir yönlendirme talimatları değilsiniz.
jyavenard

7
@jyavenard: Soru bash olarak etiketlendiğinden , daha özlü bash'a özgü yönlendirme gösterimi &>/dev/null. Ancak, size katılıyorum, gerçekten önemli olan şey taşınabilirlik, cevabımı buna göre düzenledim, şimdi standart sh yönlendirmesini kullanarak >/dev/null 2>&1.
GregV

bu cevabı daha da geliştirmek için iki şey yaparım: 1: Josh'un cevabı gibi basitleştirmek için "&>" kullanın. 2: okunabilirlik için yankı önüne bir sekme koyarak {} 'i fazladan bir satıra
ayırın

Herkes isterse bu astarı bash fonksiyonuna koydum
eşittir

94

Bunu kolaylaştıran .bashrc dosyamda tanımlanan bir fonksiyonum var.

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

İşte nasıl kullanıldığına dair bir örnek (benim .bash_profile.)

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

Ne yapar &>?
Saad Malik


&>Bash sürümünüzde mevcut olmayabilir. Marcello'nun kodu iyi çalışmalıdır; aynı şeyi yapar.
Josh Strater

3
Yerleşik ve ayrılmış sözcüklerde başarısız: Bunu thenörneğin sözcüğü ile deneyin . Yürütülebilir dosyanın var olmasını istiyorsanız bu yanıta bakın $PATH.
Tom Hale

84

$PATHDeğişken içindeki dizinlerden birinde var olup olmadığını bilmek veya değişkenin mutlak yerini bilmek isteyip istemediğinize bağlıdır . $PATHDeğişkende olup olmadığını bilmek istiyorsanız ,

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

aksi takdirde kullanın

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

/dev/null/İlk örnekte yeniden yönlendirme , whichprogramın çıktısını bastırır .


22
Yorumumda belirtilen nedenlerle gerçekten "hangisini" kullanmamalısınız.
lhunath

39

@ Lhunath ve @ GregV'nin cevaplarını genişleterek, bu kontrolü bir ififadeye kolayca koymak isteyenlerin kodu :

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

Bunu nasıl kullanacağınız aşağıda açıklanmıştır:

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

13
Öğrenme ve geliştirme istekliliği ödüllendirilmelidir. +1 Bu temiz ve basit. Ekleyebileceğim tek şey command, biraz mantıksız olabilecek takma adlar için bile başarılı olmasıdır. Etkileşimli bir kabukta varlığını kontrol etmek, onu bir komut dosyasına taşıdığınızdan farklı sonuçlar verir.
Palec

1
Ben sadece test ve shopt -u expand_aliasestakma adlar gizler kullanarak / gizler ( alias ls='ls -F'başka bir cevap yukarıda belirtildiği gibi ) ve shopt -s expand_aliasesonları giderir command -v. Bu nedenle, belki de kontrol öncesinde ve sonra ayarlanmadan önce ayarlanmalıdır, ancak komut çağrısının çıktısını açıkça yakalamaz ve döndürmezseniz, işlev dönüş değerini etkileyebilir.
dragon788


16

Kullanmak için hash, @lhunath anlaşılacağı gibi bir Bash komut:

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

Bu komut dosyası çalışır hashve en son kaydedilen komutun çıkış kodunun $?eşit olup olmadığını denetler 1. Eğer hashbulamazsa foo, çıkış kodu olacaktır 1. Varsa foo, çıkış kodu0 .

&> /dev/nullyönlendirmeleri standart hatasını ve standart çıktıyı gelen hashbu ekranda görünmez şekilde ve echo >&2standart hata mesajı yazar.


8
Neden sadece if hash foo &> /dev/null; then ...?
Beni Cherniavsky-Paskin

9

Erişebileceğim kutuda çalışmak için önceki cevapları hiç almadım. Birincisi, typekuruldu (ne moreyapıyor). Yani yerleşik yönerge gereklidir. Bu komut benim için çalışıyor:

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

3
Köşeli ayraçlar ifsözdiziminin bir parçası değildir , sadece kullanın if builtin type -p vim; then .... Ve backticks gerçekten eski ve onaylanmamış sözdizimi, tüm modern sistemlerde $()bile desteklenmektedir sh.
nyuszika7h

9

Birden fazla bağımlılığı kontrol edin ve durumu son kullanıcılara bildirin

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

Örnek çıktı:

latex     OK
pandoc    missing

10Maksimum komut uzunluğunu ayarlayın . Otomatik değil, çünkü bunu yapmak için ayrıntılı olmayan bir POSIX yolu göremiyorum: Bash'ta boşlukla ayrılmış bir tablonun sütunlarını nasıl hizalayabilirim?

Bazı aptpaketlerin kurulu olup olmadığını kontrol edin dpkg -sve aksi halde kurun .

Bkz: apt-get paketinin kurulu olup olmadığını kontrol edin ve Linux'ta değilse kurun

Daha önce şu adreste bahsedildi: Bir programın Bash betiğinden olup olmadığını nasıl kontrol edebilirim?


1
Bunu yapmanın ayrıntılı olmayan yolu: 1) genişlik belirleyicisinden kurtulun; 2) komut adınızın printf öğesinden sonra bir boşluk ekleyin; 3) for döngüsünü boruya column -t(util-linux'un bir parçası).
Patrice Levesque

8

Programın varlığını kontrol ederseniz, muhtemelen daha sonra yine de çalıştıracaksınız. Neden ilk etapta çalıştırmaya çalışmıyorsunuz?

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

Programın çalışıp çalışmadığını yalnızca PATH dizinlerine ve dosya izinlerine bakmaktan daha güvenilir bir şekilde kontrol edin.

Ayrıca, sürümü gibi programınızdan bazı yararlı sonuçlar alabilirsiniz.

Tabii ki dezavantajları bazı programların başlatılması için ağır olabileceği ve bazılarının --versionhemen (ve başarılı bir şekilde) çıkma seçeneğinin olmamasıdır.


6

hash foo 2>/dev/null: Z kabuğu (Zsh), Bash, Dash ve ash ile çalışır .

type -p foo: Z kabuğu, Bash ve ash ( BusyBox ) ile çalışıyor gibi görünüyor , ancak Dash ile değil ( -pargüman olarak yorumlanıyor ).

command -v foo: Z kabuğu, Bash, Dash ile çalışır, ancak ash (BusyBox) ( -ash: command: not found) ile çalışmaz .

Ayrıca builtinkül ve Dash ile mevcut olmadığını da unutmayın .


4

Aşağıdakileri yapabiliyorsanız Bash yerleşiklerini kullanın:

which programname

...

type -P programname

15
Ha? whichBash yerleşkesi değil.
tripleee

-P program adı tercih edilecektir, kabul edilen cevaba bakınız
RobertG

@RobertG Tüm gördüğüm -PPOSIX değil. Neden type -Ptercih edilir?
mikemaccana

Ben bash-özgü önceki yoruma cevap niyetinde olduğu gibi "bash ortamlarında tercih edilmek" i ifade etmeliydim. Her neyse, bu yıllar önceydi - Sanırım sadece, yine, "accpeted" olarak işaretlenmiş cevaba işaret etmeliyim
RobertG

4

-vPOSIX_BUILTINS seçeneği sınanacak şekilde ayarlanmışsa komut iyi çalışır <command>, ancak değilse başarısız olabilir. (Benim için yıllarca çalıştı, ama son zamanlarda işe yaramadığı bir yerde karşılaştım.)

Aşağıdakilerin daha başarısız olduğunu düşünüyorum:

test -x $(which <command>)

Üç şeyi test ettiğinden: yol, varlık ve yürütme izni.


Çalışmıyor. yüklü ve çalıştırılabilir olmasına rağmen çalıştığım docker kapsayıcısına yüklenmemiş olsa bile test -x $(which ls)0 döndürür .test -x $(which sudo)lssudo
algal

@algal Sanırım tırnak işareti kullanmanız gerekiyor, yanitest -x "$(which <command>)"
JoniVR

@algal Belki lsde takma addır ? Komutun parametresi varsa işe yarayacağını sanmıyorum.
AnthonyC

3

İlgilenenler için, yüklü bir kitaplığı algılamak istiyorsanız önceki yanıtlardaki yöntemlerden hiçbiri çalışmaz. Ya (fiziksel olarak üstbilgi dosyaları ve benzeri için) yolu veya böyle bir şey (Debian tabanlı bir dağıtımda iseniz) fiziksel olarak kontrol ile bırakıldığını hayal:

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

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

Yukarıdan görebileceğiniz gibi, sorgudan bir "0" cevabı paketin kurulu olmadığı anlamına gelir. Bu "grep" işlevidir - "0" bir eşleşme bulunduğunu, "1" eşleşmenin bulunmadığını gösterir.


10
Ancak, anti-desen cmd; if [ $? -eq 0 ]; thenyeniden düzenlenmesi gerekirif cmd; then
üçlü

Bu sadece dpkgveya aracılığıyla yüklenen kütüphaneler için geçerlidirapt
Weijun Zhou

3

Burada bir ton seçenek var, ama hızlı bir gömlek olmamasına şaşırdım. Senaryolarımın başında kullandığım şey bu:

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

Bu, burada seçilen cevaba ve başka bir kaynağa dayanmaktadır.


2

Sarkan aliases nedeniyle taşınabilir ve% 100 güvenilir bir yol olmadığını söyleyebilirim . Örneğin:

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

Tabii ki, sadece sonuncusu sorunlu (Ringo'ya suç yok!). Ancak hepsi alias, bakış açısından geçerli eslerdir command -v.

Böyle sarkan olanları reddetmek ringoiçin, kabuk yerleşik aliaskomutunun çıktısını ayrıştırıp bunlara geri dönmeliyiz ( burada command -vdaha üstün değil alias.) Bunun için taşınabilir bir çözüm ve hatta bir Bash- özel çözüm oldukça sıkıcıdır.

Böyle bir çözümün koşulsuz olarak reddedileceğini unutmayın alias ls='ls -F':

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

İyi bir nokta. Ancak, bir bash betiğinin içinden çalıştırıldığında takma adlar görünmez.
Basil Musa

1
Bir sorun da var, 'takma ad' komutu işaretlendiğinde false döndürecektir. Ne zaman doğru dönmeli. Örnek: "takma ad" testi
Basil Musa

2
Ben sadece test ve kullanarak shopt -u expand_aliasesbu takma adları yok sayar / gizler ve shopt -s expand_aliasesaracılığıyla gösterir command -v.
dragon788

2

Bu, programın var olup olmadığını konuma göre söyleyecektir:

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

Evet, sevrer, Open suse, centos, Debian
Klevin

Sözdizimi vurgulaması "echo" satırında kapalıdır. Çözüm nedir? Bash betiğinin farklı olması mı gerekiyor?
Peter Mortensen

@PeterMortensen Sözdizimi vurgulama kapalı çünkü bir dize olduğunu tanımıyor.
Adrien

1

whichKomut yararlı olabilir. hangi adam

Yürütülebilir dosya bulunursa 0, yürütülebilir ya da yürütülebilir değilse 1 döndürür:

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

Güzel bir şey which, çalıştırılabilir ortamda whichçalıştırılabilir ortamda kullanılabilir olup olmadığını anlamasıdır - birkaç sorundan tasarruf sağlar ...


Eğer foo adında bir yürütülebilir dosya arıyorsanız hangisini kullanın, ancak belirli bir dosyayı / path / to / a / named / foo dosyasını kontrol etmek istiyorsanız cevabımı görün. Ayrıca, herhangi bir tam teşekküllü kurulumda mevcut olmasına rağmen, bazı minimum sistemlerde bulunmayabileceğini unutmayın ...
dmckee --- eski moderatör yavru kedi

9
Hangi çıkış durumuna güvenmeyin. Birçok işletim sistemi 0'dan başka bir çıkış durumu bile ayarlamayan bir sisteme sahiptir.
lhunath

1

Debian kurulumum sunucusu :

Birden fazla paket aynı adı içerdiğinde sorun yaşadım.

Örneğin apache2. Bu benim çözümümdü:

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

Sizler / kızlar sizin cevaplarınızdaki şeyleri işe yaramıyorsa ve saçınızı sırtınızdan çekiyorsanız, aynı komutu kullanarak bash -c . Sadece bu somnambular deliryuma bakın. $ (Alt-komut) çalıştırdığınızda gerçekten olan budur:

İlk. Size tamamen farklı çıktılar verebilir.

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

İkinci. Size hiç çıktı veremez.

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

Farklılıklar, kabuğun etkileşimli ve etkileşimli olmayan modu arasındaki farktan kaynaklanır. ~ / .Bashrc dosyanız yalnızca kabuk giriş yapmadığında ve etkileşimli olduğunda okunur. İkincisi garip görünüyor, çünkü bu PATH ortam değişkenindeki bir farktan kaynaklanmalıdır, ancak alt kabuklar çevreyi miras alır.
Palec

Benim durumumda .bashrcbir [ -z "$PS1" ] && returnprepended var, # If not running interactively, don't do anythingbu yüzden sanırım neden interaktif olmayan modda bashrc açık kaynak bile yardımcı olmaz. Sorun, bir ss64.com/bash/source.html nokta işleci ile bir komut dosyası çağırarak çözülebilir. ./script.sh , ancak bu her seferinde yazmak hatırlamak istediğiniz bir şey değildir.
user619271

1
Kaynaklanmaması gereken komut dizilerinin kaynaklanması kötü bir fikirdir. Söylemeye çalıştığım tek şey, cevabınızın sorulan soru ile çok az ilgisi ve Bash ve onun (etkileşimli olmayan) moduyla çok ilgisi olduğu.
Palec

Bu durumlarda neler olup bittiğini açıklarsa, bir cevaba yararlı bir ek olacaktır.
Palec

0

Hash-variant'ın bir tuzağı vardır: Komut satırına örneğin şunu yazabilirsiniz:

one_folder/process

işlemin yürütülmesi. Bunun için one_folder öğesinin üst klasörü $ PATH olmalıdır . Ancak bu komutu hash etmeye çalıştığınızda, her zaman başarılı olacaktır:

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

4
"Bunun için one_folder öğesinin üst klasörü içinde olmalı $PATH" —Bu tamamen yanlış. Dene. Bunun çalışması için, geçerli klasörde one_folder olmalıdır .
Joker

0

İkincisi "komut -v" kullanımını. Örneğin şöyle:

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

Git'in CI sunucumuzu dağıtmanın bir parçası olarak kurulduğunu kontrol etmek zorunda kaldım . Son Bash betiğim şöyleydi (Ubuntu sunucusu):

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

3
Koşullu oldukça işe yaramaz, apt-get'i çalıştırmak için başlangıç ​​zamanını modulo, apt-get tatmin edecek ve git-core zaten kurulu ise çıkacaktır.
üçlü

3
Başlangıç ​​zamanı ihmal edilemez, ancak daha önemli motivasyon sudo: şartlı olmadan, her zaman durur ve şifre ister (son zamanlarda bir sudo yapmadıysanız). BTW, sudo -p "Type your password to install missing git-core: "istemin maviden çıkmaması yararlı olabilir .
Beni Cherniavsky-Paskin

0

Bash'ları taklit etmek type -P cmdiçin POSIX uyumlu kullanabiliriz 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
Bu neden iptal ediliyor? Bu sizin için hangi sistemlerde çalışıyor? typeBir gibi görünüyor builtinbu çünkü çalışamaz böylece en kabuklarda envkullanır execvpçalıştırmak commandböylece commandbir olamaz builtin(ve builtinher zaman aynı ortamı içinde idare edilecek). Bu benim için başarısız bash, ksh93, zsh, busybox [a]shve dashhepsini sağlayan typebir kabuk yerleşiği olarak.
Adrian Frühwirth

0

Kullanılabilir herhangi bir harici typekomut yoksa ( burada verildiği gibi ) POSIX uyumlu kullanabiliriz 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

En azından Bash 4.2.24 kullanan Mac OS Xv10.6.8'de (Snow Leopard) (2)command -v ls eşleşmiyor /bin/ls-temp.


0

Bir program varsa durumunda denetlemek istediğiniz bir programı ve gerçekten bir Bash yerleşik komutu , daha sonra command, typevehash olmayan komutlar yerleşik için onlar gibi tüm return 0 çıkış durumu test etmek için benimsedikleri görülmüştür.

Örneğin, yerleşik zaman komutundan daha fazla özellik sunan bir zaman programı vardır . Programın var olup olmadığını kontrol etmek için aşağıdaki örnekte olduğu gibi kullanılmasını öneririm :which

# 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

Aynı sorunun bir Makefile içinde cevaplanmasını istedim.

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

-1

Senaryo

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

Sonuç

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

-1

Bunu kullanıyorum, çünkü çok kolay:

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

veya

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

Standart çıktıya kabuk yerleşiklerini ve programların yankı durumunu kullanır ve standart hataya hiçbir şey kullanmaz. Diğer yandan, bir komut bulunmazsa, durumu yalnızca standart hataya yansıtır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.