Bagaimana saya bisa memeriksa apakah ada program dari skrip Bash?


2211

Bagaimana saya memvalidasi bahwa ada program, dengan cara yang akan mengembalikan kesalahan dan keluar, atau melanjutkan dengan skrip?

Sepertinya itu seharusnya mudah, tapi itu membuatku bingung.


Apa itu "program"? Apakah itu termasuk fungsi dan alias? whichmengembalikan true untuk ini. typetanpa argumen juga akan mengembalikan true untuk kata-kata yang dicadangkan dan shell builtin. Jika "program" berarti "excutable in $PATH", maka lihat jawaban ini .
Tom Hale

Jawaban:


3055

Menjawab

Kompatibel dengan POSIX:

command -v <the_command>

Untuk lingkungan spesifik Bash:

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

Penjelasan

Hindari which. Tidak hanya itu proses eksternal yang Anda luncurkan untuk melakukan sangat sedikit (artinya seperti bawaan hash, typeatau commandlebih murah), Anda juga dapat mengandalkan bawaan untuk benar-benar melakukan apa yang Anda inginkan, sementara efek dari perintah eksternal dapat dengan mudah bervariasi dari sistem ke sistem.

Mengapa peduli

  • Banyak sistem operasi whichyang bahkan tidak menetapkan status keluar , yang berarti if which foobahkan tidak akan berfungsi di sana dan akan selalu melaporkan yang fooada, bahkan jika tidak (perhatikan bahwa beberapa shell POSIX juga melakukan hal ini hash).
  • Banyak sistem operasi whichmelakukan hal-hal kebiasaan dan jahat seperti mengubah output atau bahkan menghubungkan ke manajer paket.

Jadi, jangan gunakan which. Alih-alih gunakan salah satu dari ini:

$ 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-note: beberapa akan menyarankan 2>&-adalah sama 2>/dev/nulltetapi lebih pendek - ini tidak benar . 2>&-Menutup FD 2 yang menyebabkan kesalahan dalam program ketika mencoba untuk menulis ke stderr, yang sangat berbeda dari berhasil menulis ke sana dan membuang output (dan berbahaya!))

Jika hash bang /bin/shAnda maka Anda harus peduli dengan apa yang dikatakan POSIX. typedan hashkode keluar tidak terlalu didefinisikan dengan baik oleh POSIX, dan hashterlihat berhasil keluar ketika perintah belum ada (belum melihat ini dengan sebelumnya type). commandStatus keluar didefinisikan dengan baik oleh POSIX, sehingga seseorang mungkin paling aman untuk digunakan.

Jika skrip Anda menggunakan bash, aturan POSIX tidak terlalu penting lagi dan keduanyatype dan hashmenjadi sangat aman untuk digunakan. typesekarang memiliki -Puntuk mencari hanya PATHdan hashmemiliki efek samping bahwa lokasi perintah akan di-hash (untuk pencarian lebih cepat saat Anda menggunakannya), yang biasanya merupakan hal yang baik karena Anda mungkin memeriksa keberadaannya agar benar-benar menggunakannya .

Sebagai contoh sederhana, inilah fungsi yang berjalan gdatejika ada, jika tidak date:

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

35
@ Geert: Bagian &> / dev / null menyembunyikan pesan 'ketik' yang dipancarkan ketika 'foo' tidak ada. > & 2 pada echo memastikan untuk mengirim pesan kesalahan ke kesalahan standar alih-alih output standar; karena itulah konvensi. Keduanya muncul di terminal Anda, tetapi kesalahan standar jelas merupakan output yang disukai untuk pesan kesalahan dan peringatan yang tidak terduga.
lhunath

5
flag -P tidak berfungsi di 'sh', misalnya stackoverflow.com/questions/2608688/…
momeara

130
Bagi mereka yang tidak terbiasa dengan pengalihan i / o 'maju' di bash: 1) 2>&- ("tutup file output deskriptor 2", yang merupakan stderr) memiliki hasil yang sama dengan 2> /dev/null; 2) >&2adalah jalan pintas untuk 1>&2, yang dapat Anda kenali sebagai "redirect stdout to stderr". Lihat halaman pengarahan ulang Panduan Script Bash Lanjutan / i untuk informasi lebih lanjut.
mikewaters

9
@mikewaters ABS terlihat cukup canggih dan menggambarkan berbagai fungsi CLI bash dan non-bash, tetapi sangat lalai dalam banyak aspek dan tidak mengikuti praktik yang baik. Saya tidak memiliki cukup ruang dalam komentar ini untuk melakukan penulisan; tapi aku bisa menyisipkan contoh acak beberapa kode BAD: while read element ; do .. done <<< $(echo ${ArrayVar[*]}), for word in $(fgrep -l $ORIGINAL *.txt), ls -l "$directory" | sed 1d , {{untuk di seq $BEGIN $END}}, ... Banyak telah mencoba untuk menghubungi penulis dan mengusulkan perbaikan tapi itu tidak ada wiki dan permintaan telah mendarat di telinga tuli.
lhunath

56
@mikewaters 2>&-adalah tidak sama dengan 2>/dev/null. Yang pertama menutup deskriptor file, sedangkan yang kedua hanya mengarahkan ke /dev/null. Anda mungkin tidak melihat kesalahan karena program mencoba memberi tahu Anda tentang stderr bahwa stderr ditutup.
nyuszika7h

577

Berikut ini adalah cara portabel untuk memeriksa apakah ada perintah $PATH dan dapat dieksekusi:

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

Contoh:

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

Pemeriksaan yang dapat dieksekusi diperlukan karena bash mengembalikan file yang tidak dapat dieksekusi jika tidak ditemukan file yang dapat dieksekusi dengan nama itu $PATH .

Juga perhatikan bahwa jika file yang tidak dapat dieksekusi dengan nama yang sama dengan yang dapat dieksekusi ada sebelumnya $PATH, dash mengembalikan yang pertama, meskipun yang terakhir akan dieksekusi. Ini adalah bug dan melanggar standar POSIX. [ Laporan bug ] [ Standar ]

Selain itu, ini akan gagal jika perintah yang Anda cari telah didefinisikan sebagai alias.


4
Akankah command -vmenghasilkan path bahkan untuk file yang tidak dapat dieksekusi? Artinya, -x benar-benar diperlukan?
einpoklum

5
@einpoklum -xmenguji apakah file tersebut dapat dieksekusi, yang merupakan pertanyaannya.
Ken Sharp

3
@ KenSharp: Tapi itu sepertinya mubazir, karena commanditu sendiri akan menguji untuk dieksekusi - bukan?
einpoklum

13
@einpoklum Ya, itu perlu. Bahkan, bahkan solusi ini dapat pecah dalam satu kasus tepi. Terima kasih sudah membawa ini padaku. tanda hubung, bash, dan zsh semua melompati file yang tidak dapat dieksekusi $PATHsaat menjalankan perintah. Namun, perilaku command -vtersebut sangat tidak konsisten. Di dasbor, ia mengembalikan file yang cocok pertama $PATH, terlepas dari apakah itu dapat dieksekusi atau tidak. Dalam bash, ia mengembalikan kecocokan yang dapat dieksekusi pertama kali $PATH, tetapi jika tidak ada, ia dapat mengembalikan file yang tidak dapat dieksekusi. Dan di zsh, itu tidak akan pernah mengembalikan file yang tidak dapat dieksekusi.
nyuszika7h

5
Sejauh yang saya tahu, dashadalah satu-satunya dari tiga yang tidak sesuai dengan POSIX; [ -x "$(command -v COMMANDNAME)"]akan bekerja di dua lainnya. Sepertinya bug ini sudah dilaporkan tetapi belum mendapat respons: bugs.debian.org/cgi-bin/bugreport.cgi?bug=874264
nyuszika7h

210

Saya setuju dengan lhunath untuk mencegah penggunaan which, dan solusinya sangat valid untuk pengguna Bash . Namun, agar lebih portabel, command -vharus digunakan sebagai gantinya:

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

Perintah commandsesuai dengan POSIX. Lihat di sini untuk spesifikasinya: perintah - jalankan perintah sederhana

Catatan: typekompatibel dengan POSIX, tetapi type -Ptidak.


3
Sama seperti di atas - exit 1;membunuh xterm, jika dipanggil dari sana.
pengguna tidak diketahui

1
Ini tidak akan berfungsi pada standar sh: Anda &> bukan instruksi pengalihan yang valid.
jyavenard

7
@jyavenard: Pertanyaannya diberi tag bash , karenanya notasi pengalihan bash-spesifik lebih ringkas &>/dev/null. Namun, saya setuju dengan Anda, yang benar-benar penting adalah portabilitas, saya telah mengedit jawaban saya sesuai, sekarang menggunakan pengalihan standar >/dev/null 2>&1.
GregV

untuk lebih meningkatkan jawaban ini, saya akan melakukan dua hal: 1: gunakan "&>" untuk menyederhanakannya, seperti jawaban Josh. 2: pecahkan {} menjadi baris tambahan, letakkan tab di depan gema, agar mudah dibaca
knocte

Saya hanya menempatkan liner yang satu ini ke fungsi bash jika ada yang mau ... github.com/equant/my_bash_tools/blob/master/tarp.bash
equant

94

Saya memiliki fungsi yang didefinisikan dalam .bashrc saya yang membuatnya lebih mudah.

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

Berikut ini contoh penggunaannya (dari saya .bash_profile.)

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

Apa yang &>dilakukan?
Saad Malik


&>mungkin tidak tersedia di versi Bash Anda. Kode Marcello seharusnya bekerja dengan baik; itu melakukan hal yang sama.
Josh Strater

3
Gagal pada bawaan dan kata-kata yang dicadangkan: Coba ini dengan kata thenmisalnya. Lihat jawaban ini jika Anda membutuhkan eksekutabel di $PATH.
Tom Hale

84

Itu tergantung pada apakah Anda ingin tahu apakah itu ada di salah satu direktori dalam $PATHvariabel atau apakah Anda tahu lokasi absolutnya. Jika Anda ingin tahu apakah itu ada dalam $PATHvariabel, gunakan

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

jika tidak gunakan

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

Pengalihan ke /dev/null/dalam contoh pertama menekan output dari whichprogram.


22
Anda benar-benar tidak boleh menggunakan "yang" karena alasan yang diuraikan dalam komentar saya.
lhunath

39

Memperluas jawaban @ lhunath dan @ GregV, inilah kode untuk orang-orang yang ingin dengan mudah memasukkan cek itu di dalam ifpernyataan:

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

Berikut cara menggunakannya:

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

13
Kesediaan untuk belajar dan meningkatkan harus dihargai. +1 Ini bersih dan sederhana. Satu-satunya hal yang dapat saya tambahkan adalah bahwa commandberhasil bahkan untuk alias, yang mungkin agak berlawanan dengan intuisi. Memeriksa keberadaan dalam shell interaktif akan memberikan hasil yang berbeda dari ketika Anda memindahkannya ke skrip.
Palec

1
Saya baru saja menguji dan menggunakan shopt -u expand_aliasesabaikan / sembunyikan alias (seperti yang alias ls='ls -F'disebutkan dalam jawaban lain) dan shopt -s expand_aliasesselesaikan melalui command -v. Jadi mungkin itu harus ditetapkan sebelum pemeriksaan dan tidak disetel setelah, meskipun itu dapat mempengaruhi nilai kembali fungsi jika Anda tidak menangkap dan mengembalikan output dari panggilan perintah secara eksplisit.
dragon788


16

Untuk menggunakan hash, seperti yang disarankan @lhunath , dalam skrip Bash:

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

Script ini berjalan hashdan kemudian memeriksa apakah kode keluar dari perintah terbaru, nilai yang disimpan $?, sama dengan 1. Jika hashtidak ditemukan foo, kode keluarnya adalah 1. Jika fooada, kode keluar akan menjadi0 .

&> /dev/nullpengalihan standar error dan output standar dari hashsehingga tidak muncul pada layar dan echo >&2menulis pesan ke standard error.


8
Kenapa tidak adil if hash foo &> /dev/null; then ...?
Beni Cherniavsky-Paskin

9

Saya tidak pernah mendapatkan jawaban sebelumnya untuk bekerja pada kotak yang saya akses. Untuk satu, typetelah diinstal (melakukan apa more). Jadi direktif builtin diperlukan. Perintah ini bekerja untuk saya:

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

3
Kurung bukan bagian dari ifsintaks, cukup gunakan if builtin type -p vim; then .... Dan backtick adalah sintaks yang benar-benar kuno dan usang, $()didukung bahkan oleh shsemua sistem modern.
nyuszika7h

9

Periksa beberapa dependensi dan informasikan status ke pengguna akhir

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

Output sampel:

latex     OK
pandoc    missing

Sesuaikan dengan 10panjang perintah maksimum. Itu tidak otomatis, karena saya tidak melihat cara POSIX non-verbose untuk melakukannya: Bagaimana saya bisa meluruskan kolom dari tabel yang dipisahkan ruang di Bash?

Periksa apakah beberapa aptpaket diinstal dengan dpkg -sdan instal sebaliknya .

Lihat: Periksa apakah paket apt-get diinstal dan kemudian instal jika tidak di Linux

Itu sebelumnya disebutkan di: Bagaimana saya bisa memeriksa apakah ada program dari skrip Bash?


1
Cara non-verbal untuk melakukannya: 1) singkirkan specifier lebar; 2) tambahkan spasi setelah printf nama perintah Anda; 3) pipa untuk loop Anda ke column -t(bagian dari util-linux).
Patrice Levesque

8

Jika Anda memeriksa keberadaan program, Anda mungkin akan menjalankannya nanti. Mengapa tidak mencoba menjalankannya?

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

Ini adalah pemeriksaan yang lebih dapat dipercaya bahwa program berjalan daripada hanya melihat direktori PATH dan izin file.

Plus, Anda bisa mendapatkan hasil yang bermanfaat dari program Anda, seperti versinya.

Tentu saja kekurangannya adalah bahwa beberapa program bisa berat untuk memulai dan beberapa tidak memiliki --versionopsi untuk segera (dan berhasil) keluar.


6

hash foo 2>/dev/null: bekerja dengan Z shell (Zsh), Bash, Dash dan ash .

type -p foo: tampaknya berfungsi dengan Z shell, Bash dan ash ( BusyBox ), tetapi tidak Dash (ini diinterpretasikan-p sebagai argumen).

command -v foo: bekerja dengan Z shell, Bash, Dash, tetapi tidak abu (BusyBox) (-ash: command: not found ).

Perhatikan juga bahwa builtintidak tersedia dengan abu dan Dash.


4

Gunakan Bash bawaan jika Anda dapat:

which programname

...

type -P programname

15
Hah? whichbukan Bash builtin.
tripleee

ketik -P nama program lebih disukai, lihat jawaban yang diterima
RobertG

@ RobertTG Yang saya lihat adalah itu -Pbukan POSIX. Mengapa type -Plebih disukai?
mikemaccana

Saya seharusnya mengatakan bahwa "lebih disukai di lingkungan bash" - karena saya bermaksud untuk menjawab komentar sebelumnya khusus bash. Bagaimanapun, itu bertahun-tahun yang lalu - saya kira saya harus, sekali lagi, mengarahkan Anda ke jawaban yang ditandai sebagai "tertipu"
RobertG

4

Perintah -vberfungsi dengan baik jika opsi POSIX_BUILTINS diatur untuk<command> untuk menguji, tetapi bisa gagal jika tidak. (Ini telah bekerja untuk saya selama bertahun-tahun, tetapi saya baru-baru ini bertemu dengan yang tidak berfungsi.)

Saya menemukan yang berikut ini lebih anti-gagal:

test -x $(which <command>)

Karena tes untuk tiga hal: jalur, keberadaan dan izin eksekusi.


Tidak bekerja test -x $(which ls)mengembalikan 0, seperti halnya test -x $(which sudo), meskipun lssudah diinstal dan dapat dijalankan dan sudobahkan tidak diinstal dalam wadah buruh pelabuhan tempat saya menjalankan.
algal

@algal Anda harus menggunakan tanda kutip, saya kiratest -x "$(which <command>)"
JoniVR

@algal Mungkin lsalias? Saya tidak berpikir itu akan berhasil jika perintah memiliki parameter.
AnthonyC

3

Bagi yang berminat, tidak ada metodologi dalam jawaban sebelumnya yang berfungsi jika Anda ingin mendeteksi pustaka yang diinstal. Saya membayangkan Anda dibiarkan dengan memeriksa path secara fisik (berpotensi untuk file header dan semacamnya), atau sesuatu seperti ini (jika Anda menggunakan distribusi berbasis Debian):

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

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

Seperti yang dapat Anda lihat dari atas, jawaban "0" dari kueri berarti paket tersebut tidak diinstal. Ini adalah fungsi dari "grep" - a "0" berarti kecocokan ditemukan, "1" berarti tidak ada kecocokan yang ditemukan.


10
Namun, anti-pola cmd; if [ $? -eq 0 ]; thenharus di refactored keif cmd; then
tripleee

Ini hanya berfungsi untuk lib yang diinstal melalui dpkgatauapt
Weijun Zhou

3

Ada banyak pilihan di sini, tapi saya terkejut tidak ada satu baris cepat. Inilah yang saya gunakan di awal skrip saya:

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

Ini didasarkan pada jawaban yang dipilih di sini dan sumber lain.


2

Saya akan mengatakan tidak ada cara portabel dan 100% dapat diandalkan karena menggantung aliases. Sebagai contoh:

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

Tentu saja, hanya yang terakhir yang bermasalah (jangan tersinggung oleh Ringo!). Tapi semuanya valid aliasdari sudut pandang command -v.

Untuk menolak yang menjuntai seperti ringo, kita harus mengurai output dari perintah built-in shell aliasdan recurse ke dalamnya ( command -vbukan superior untukalias sini.) Tidak ada solusi portabel untuk itu, dan bahkan Bash- solusi spesifik agak membosankan.

Perhatikan bahwa solusi seperti ini akan menolak tanpa syarat alias ls='ls -F':

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

Poin yang bagus. Namun, ketika dijalankan dari dalam skrip bash, alias tidak terlihat.
Basil Musa

1
Ada juga masalah, itu akan mengembalikan false ketika perintah 'alias' dicentang. Kapan itu harus kembali benar. Contoh: test "alias"
Basil Musa

2
Saya baru saja menguji dan menggunakan shopt -u expand_aliasesabaikan / sembunyikan alias ini dan tampilkan shopt -s expand_aliasesmelalui command -v.
dragon788

2

Ini akan memberi tahu menurut lokasi jika program ada atau tidak:

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

Ya saya menambahkan perintah ini jika Anda perlu menginstal paket di sevrer, Buka suse, centos, Debian
Klevin Kona

Penyorotan sintaks tidak aktif di baris "echo". Apa solusinya? Apakah itu menyarankan skrip Bash harus berbeda?
Peter Mortensen

@PeterMortensen Syntax highlighting tidak aktif karena tidak mengenali itu string.
Adrien

1

The whichperintah mungkin berguna. pria yang

Ini mengembalikan 0 jika executable ditemukan dan mengembalikan 1 jika tidak ditemukan atau tidak dapat dieksekusi:

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

Yang menyenangkan tentang itu whichadalah mengetahui apakah executable tersedia di lingkungan yang whichdijalankan - ini menghemat beberapa masalah ...


Gunakan yang jika Anda mencari executable bernama foo, tetapi lihat jawaban saya jika Anda ingin memeriksa file / path / ke / a / bernama / foo tertentu. Juga perhatikan bahwa yang mungkin tidak tersedia pada beberapa sistem minimal, meskipun harus ada pada setiap instalasi lengkap ...
dmckee --- ex-moderator kitten

9
Jangan mengandalkan status keluar yang. Banyak sistem operasi memiliki yang yang bahkan tidak menetapkan status keluar selain 0.
lhunath

1

Pengaturan saya untuk seorang Debian server :

Saya memiliki masalah ketika beberapa paket berisi nama yang sama.

Sebagai contoh apache2. Jadi ini solusi saya:

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

Jika kalian / gals tidak bisa mendapatkan jawaban di sini untuk bekerja dan menarik rambut dari punggungmu, cobalah untuk menjalankan perintah yang sama menggunakan bash -c . Lihat saja delirium somnambular ini. Inilah yang sebenarnya terjadi ketika Anda menjalankan $ (sub-perintah):

Pertama. Ini dapat memberi Anda output yang sama sekali berbeda.

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

Kedua. Itu tidak bisa memberi Anda hasil sama sekali.

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

Perbedaan tersebut disebabkan oleh perbedaan antara mode shell interaktif dan non-interaktif. ~ / .Bashrc Anda hanya dibaca ketika shell non-login dan interaktif. Yang kedua terlihat aneh, karena ini harus disebabkan oleh perbedaan dalam variabel lingkungan PATH, tetapi subkulit mewarisi lingkungan.
Palec

Dalam kasus saya .bashrcada yang [ -z "$PS1" ] && returnditulis oleh # If not running interactively, don't do anythingjadi saya kira itu adalah alasan mengapa bahkan sumber eksplisit bashrc dalam mode non-interaktif tidak membantu. Masalahnya dapat diatasi dengan memanggil skrip dengan operator titik ss64.com/bash/source.html. ./script.sh tapi itu bukan hal yang ingin diingat untuk mengetik setiap kali.
user619271

1
Sumber skrip yang tidak seharusnya bersumber adalah ide yang buruk. Yang saya coba katakan adalah bahwa jawaban Anda tidak ada hubungannya dengan pertanyaan yang diajukan dan banyak hubungannya dengan Bash dan mode (non-) interaktifnya.
Palec

Jika itu menjelaskan apa yang terjadi dalam kasus-kasus ini, itu akan menjadi tambahan yang bermanfaat untuk sebuah jawaban.
Palec

0

Varian hash memiliki satu perangkap: Di baris perintah Anda dapat misalnya mengetik

one_folder/process

untuk memiliki proses dieksekusi. Untuk ini folder induk dari one_folder harus dalam $ PATH . Tetapi ketika Anda mencoba untuk hash perintah ini, itu akan selalu berhasil:

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

4
"Untuk ini folder induk one_folder harus dalam $PATH" —Ini benar-benar tidak akurat. Cobalah. Agar ini berfungsi, one_folder harus ada di direktori saat ini .
Wildcard

0

Saya kedua penggunaan "command -v". Misal seperti ini:

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

Saya harus memeriksa apakah Git diinstal sebagai bagian dari penerapan server CI kami . Skrip Bash terakhir saya adalah sebagai berikut (server Ubuntu):

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

3
Syaratnya agak tidak berguna, modulo waktu startup untuk menjalankan apt-get, karena apt-get akan puas dan keluar jika git-core sudah diinstal.
tripleee

3
Waktu startup-nya tidak dapat diabaikan, tetapi motivasi yang lebih penting adalah sudo: tanpa syarat, itu akan selalu berhenti dan meminta kata sandi (kecuali jika Anda melakukan sudo baru-baru ini). BTW, mungkin berguna untuk melakukannya sudo -p "Type your password to install missing git-core: "agar prompt tidak muncul tiba-tiba.
Beni Cherniavsky-Paskin

0

Untuk meniru Bash type -P cmd, kita bisa menggunakan yang sesuai dengan POSIX 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
Mengapa ini dibalik? Pada sistem apa ini bekerja untuk Anda? typetampaknya menjadi builtinsebagian besar shell jadi ini tidak bisa berfungsi karena envdigunakan execvpuntuk menjalankan commandjadi commandtidak bisa menjadi builtin(dan builtinakan selalu dijalankan dalam lingkungan yang sama). Ini gagal untuk saya di bash, ksh93, zsh, busybox [a]shdan dashsemua yang menyediakan typesebagai builtin shell.
Adrian Frühwirth

0

Jika tidak ada typeperintah eksternal yang tersedia (seperti yang diterima begitu saja di sini ), kita dapat menggunakan POSIX compliant 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

Setidaknya pada Mac OS X v10.6.8 (Snow Leopard) menggunakan Bash 4.2.24 (2) command -v lstidak cocok dengan yang dipindahkan /bin/ls-temp.


0

Jika Anda ingin memeriksa apakah suatu program ada dan benar-benar sebuah program, bukan perintah bawaan Bash , maka command, typedanhash tidak yang sesuai untuk menguji karena mereka semua kembali 0 status keluar untuk built-in perintah.

Sebagai contoh, ada waktu Program yang menawarkan fitur lebih dari waktu built-in perintah. Untuk memeriksa apakah program itu ada, saya akan menyarankan menggunakan whichseperti pada contoh berikut:

# 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

Saya ingin pertanyaan yang sama dijawab tetapi dijalankan dalam Makefile.

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

-1

Naskah

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

Hasil

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

-1

Saya menggunakan ini, karena sangat mudah:

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

atau

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

Ia menggunakan shell builtins dan status gema program untuk output standar dan tidak ada kesalahan standar. Di sisi lain, jika suatu perintah tidak ditemukan, itu hanya status gema kesalahan standar.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.