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

223

Saya sedang mengerjakan sistem Ubuntu dan saat ini inilah yang saya lakukan:

if ! which command > /dev/null; then
   echo -e "Command not found! Install? (y/n) \c"
   read
   if "$REPLY" = "y"; then
      sudo apt-get install command
   fi
fi

Apakah ini yang akan dilakukan kebanyakan orang? Atau ada solusi yang lebih elegan?

John Jiang
sumber
7
Nama perintah tidak selalu mencerminkan nama paket milik mereka. Apa tujuan Anda yang lebih besar? Mengapa Anda tidak mencoba menginstalnya saja, dan hal terburuknya tidak, karena sudah diinstal.
viam0Zah
8
Untungnya, instalasi apt-get idempoten, jadi aman untuk menjalankannya dan tidak khawatir tentang apakah itu diinstal atau tidak.
David Baucum
Komentar @ DavidBaucum harus menjadi jawaban yang akan mendapatkan suara terbanyak.
Nirmal
@Nirmal, jawaban dibuat.
David Baucum
1
Terkait, Anda harus menggunakan command -v <command>; tidak which <command>. Lihat juga Periksa apakah ada program dari skrip Bash .
jww

Jawaban:

314

Untuk memeriksa apakah packagenamesudah diinstal, ketik:

dpkg -s <packagename>

Anda juga dapat menggunakan dpkg-queryyang memiliki output yang lebih rapi untuk tujuan Anda, dan menerima kartu liar juga.

dpkg-query -l <packagename>

Untuk menemukan paket apa yang dimiliki command, cobalah:

dpkg -S `which <command>`

Untuk detail lebih lanjut, lihat artikel Cari tahu apakah paket diinstal di Linux dan lembar cheat dpkg .

viam0Zah
sumber
32
Jika Anda sebagai orang menginginkan NON-program ini, Anda dapat menggunakan informasi ini sebagaimana adanya. Namun Anda tidak bisa hanya mengandalkan kode pengembalian di sini untuk skrip atau output / kurangnya output sendiri untuk skrip. Anda harus memindai output dari perintah ini, membatasi kegunaannya untuk pertanyaan ini.
UpAndAdam
4
Anehnya, saya baru-baru ini menemukan bahwa dpkg-query digunakan untuk mengembalikan 1 pada paket yang hilang, sekarang (Ubuntu 12.04) mengembalikan 0, menyebabkan segala macam masalah pada jenkins saya membangun skrip penyiapan simpul! dpkg -s mengembalikan 0 pada paket yang diinstal, dan 1 pada paket tidak diinstal.
Therealstubot
18
Hei, OP meminta ifpenggunaan. Saya juga mencari ifpenggunaan.
Tomáš Zato - Reinstate Monica
1
@Therealstubot: Saya juga menggunakan Ubuntu 12.04 dan dpkg -smengembalikan 1 pada paket yang hilang dan 0 sebaliknya, sebagaimana mestinya. Bagaimana perbedaan pada versi sebelumnya (atau yang terbaru)?
MestreLion
4
sebuah catatan: dpkg -smengembalikan nol jika paket diinstal dan kemudian dihapus - dalam hal ini Status: deinstall ok config-filesatau serupa, jadi "ok" - jadi bagi saya, ini bukan tes yang aman. dpkg-query -ltampaknya tidak mengembalikan hasil yang berguna dalam kasus ini.
tajam
86

Untuk menjadi sedikit lebih eksplisit, inilah sedikit skrip bash yang memeriksa sebuah paket dan memasangnya jika diperlukan. Tentu saja, Anda dapat melakukan hal-hal lain setelah mengetahui bahwa paket tersebut hilang, seperti hanya keluar dengan kode kesalahan.

REQUIRED_PKG="some-package"
PKG_OK=$(dpkg-query -W --showformat='${Status}\n' $REQUIRED_PKG|grep "install ok installed")
echo Checking for $REQUIRED_PKG: $PKG_OK
if [ "" = "$PKG_OK" ]; then
  echo "No $REQUIRED_PKG. Setting up $REQUIRED_PKG."
  sudo apt-get --yes install $REQUIRED_PKG 
fi

Jika skrip berjalan dalam GUI (misalnya skrip Nautilus), Anda mungkin ingin mengganti permintaan 'sudo' dengan yang 'gksudo'.

Urhixidur
sumber
5
--force-yessepertinya ide yang buruk. Dari halaman manual: "Ini adalah opsi berbahaya yang akan menyebabkan apt-get untuk melanjutkan tanpa disuruh jika melakukan sesuatu yang berpotensi berbahaya. Ini tidak boleh digunakan kecuali dalam situasi yang sangat khusus. Menggunakan --force-yes berpotensi menghancurkan sistem Anda ! " Menggunakannya dalam skrip membuatnya lebih buruk.
mengurangi aktivitas
68

One-liner ini mengembalikan 1 (diinstal) atau 0 (tidak diinstal) untuk paket 'nano' ..

$(dpkg-query -W -f='${Status}' nano 2>/dev/null | grep -c "ok installed")

bahkan jika paket tidak ada / tidak tersedia.

Contoh di bawah ini menginstal paket 'nano' jika tidak diinstal ..

if [ $(dpkg-query -W -f='${Status}' nano 2>/dev/null | grep -c "ok installed") -eq 0 ];
then
  apt-get install nano;
fi
Seb
sumber
4
Variasi saya dalam hal ini:dpkg-query -W -f='${Status}' MYPACKAGE | grep -q -P '^install ok installed$'; echo $?
ThorSummoner
@ Tumormon: peduli untuk menjelaskan mengapa milikmu lebih baik?
knocte
1
@knocte Saya tidak yakin ada argumen yang dibuat tentang menjadi lebih baik secara objektif. Meskipun saya yakin one-liner posting kata demi kata akan mengeksekusi hasil output, yang saya tidak ingin meninggalkan menggantung dalam jawaban. Satu baris yang saya tunjukkan mencontohkan mendapatkan (mencetak) hanya kode keluar.
ThorSummoner
1
@ Thormonumer Anda tidak perlu grep -Puntuk regex sederhana seperti itu.
tripleee
7
Simpler: if ! dpkg-query -W -f='${Status}' nano | grep "ok installed"; then apt install nano; fi- Tidak perlu digunakan grep -c, cukup gunakan status keluar darigrep
Stephen Ostermiller
17

dpkg -s penggunaan terprogram dengan instalasi otomatis

Saya suka dpkg -sketika keluar dengan status 1jika salah satu paket tidak diinstal, membuatnya mudah untuk diotomatisasi:

pkgs='qemu-user pandoc'
if ! dpkg -s $pkgs >/dev/null 2>&1; then
  sudo apt-get install $pkgs
fi

man dpkg sayangnya tidak mendokumentasikan status keluar, tapi saya pikir seharusnya cukup aman untuk mengandalkannya:

-s, --status package-name...
    Report status of specified package.

Satu hal yang perlu diperhatikan adalah menjalankan:

sudo apt remove <package-name>

tidak harus langsung menghapus semua file untuk beberapa paket (tetapi untuk yang lain, tidak yakin mengapa?), dan hanya menandai paket untuk dihapus.

Dalam keadaan ini, paket tampaknya masih dapat digunakan, dan karena file-nya masih ada, tetapi ditandai untuk dihapus nanti.

Misalnya jika Anda menjalankan:

pkg=certbot

sudo apt install -y "$pkg"
dpkg -s "$pkg"
echo $?

sudo apt remove -y "$pkg"
dpkg -s "$pkg"
echo $?
ls -l /usr/lib/python3/dist-packages/certbot/reporter.py

sudo apt remove --purge certbot
dpkg -s "$pkg"
echo $?
ls -l /usr/lib/python3/dist-packages/certbot/reporter.py

kemudian:

  • dua echo $?output pertama 0, hanya yang ketiga output1

  • output untuk yang pertama dpkg -s certbotberisi:

    Status: deinstall ok installed

    sedangkan yang kedua mengatakan:

    Status: deinstall ok config-files

    dan itu hanya hilang setelah pembersihan:

    dpkg-query: package 'certbot' is not installed and no information is available
  • file /etc/logrotate.d/certbotmasih ada di sistem setelah apt remove, tetapi tidak setelah --purge.

    Namun, file /usr/lib/python3/dist-packages/certbot/reporter.pytersebut tetap ada bahkan setelahnya --purge.

Saya tidak mengerti mengapa, tetapi dengan hellopaket yang kedua dpkgsetelah apt removemenunjukkan bahwa paket dia telah dihapus tanpa --purge:

dpkg-query: package 'hello' is not installed and no information is available

Dokumentasi juga sangat tidak jelas, misalnya:

sudo apt dselect-upgrade

tidak menghapus certbotketika itu ditandai deinstall, meskipun man apt-gettampaknya menunjukkan bahwa:

dselect-upgradedigunakan bersama dengan front-end packaging tradisional Debian, dselect (1). dselect-upgrade mengikuti perubahan yang dilakukan oleh dselect (1) ke bidang Status paket yang tersedia, dan melakukan tindakan yang diperlukan untuk mewujudkan keadaan itu (misalnya, penghapusan yang lama dan pemasangan paket baru).

Lihat juga:

Diuji pada Ubuntu 19.10.

aptPaket python

Ada paket Python 3 pra-instal yang disebut aptdi Ubuntu 18.04 yang memperlihatkan antarmuka Python apt!

Sebuah skrip yang memeriksa apakah sebuah paket diinstal dan menginstalnya jika tidak dapat dilihat di: Cara menginstal paket menggunakan API python-apt

Berikut ini adalah salinan untuk referensi:

#!/usr/bin/env python
# aptinstall.py

import apt
import sys

pkg_name = "libjs-yui-doc"

cache = apt.cache.Cache()
cache.update()
cache.open()

pkg = cache[pkg_name]
if pkg.is_installed:
    print "{pkg_name} already installed".format(pkg_name=pkg_name)
else:
    pkg.mark_install()

    try:
        cache.commit()
    except Exception, arg:
        print >> sys.stderr, "Sorry, package installation failed [{err}]".format(err=str(arg))

Periksa apakah executable PATHsebagai gantinya

Lihat: Bagaimana saya bisa memeriksa apakah ada program dari skrip Bash?

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
sumber
Ya, Anda tidak bisa bergantung pada kode keluar "dpkg -s". Sebagai contoh jika Anda "memasang" suatu paket, kemudian "menghapusnya" dan mencoba "dpkg -s nama paket" maka Anda akan melihat status: hapus instalasi dan keluar dari kode nol (seolah-olah terpasang). Anda harus mengurai bro output "dpkg -s".
Dmitry Shevkoplyas
@DmitryShevkoplyas terima kasih atas laporannya. Aku tidak bisa mereproduksi pada Ubuntu 19.10 dengan: sudo apt install hello; dpkg -s hello; echo $?; sudo apt remove hello; dpkg -s hello; echo $?. Bisakah Anda memberikan perincian lebih lanjut?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
1
memang - untuk test case Anda dengan paket "hello" "dpkg -s" dengan benar menunjukkan bahwa paket tersebut tidak diinstal dan memberikan kode keluar yang diharapkan "1". Tetapi coba instal / hapus centang yang sama dengan paket "certbot", maka Anda akan melihat "Status: deinstall ok config-files" sebagai output "dpkg -s" setelah "apt remove certbot" Anda dan kode keluar salah menunjukkan kepada kami "0". Asumsi saya yang salah adalah bahwa itu adalah kasus yang tepat untuk paket lain, tetapi tampaknya tidak sama untuk semua, yang bahkan lebih buruk dan kurang dapat diprediksi. Parse "dpkg -s" Anda harus (c) Yoda :)
Dmitry Shevkoplyas
11

Saya menawarkan pembaruan ini karena Ubuntu menambahkan "Personal Package Archive" (PPA) seperti pertanyaan ini dijawab, dan paket PPA memiliki hasil yang berbeda.

  1. Paket repositori Native Debian tidak diinstal:

    ~$ dpkg-query -l apache-perl
    ~$ echo $?
    1
  2. Paket PPA terdaftar di host dan diinstal:

    ~$ dpkg-query -l libreoffice
    ~$ echo $?
    0
  3. Paket PPA terdaftar di host tetapi tidak diinstal:

    ~$ dpkg-query -l domy-ce
    ~$ echo $?
    0
    ~$ sudo apt-get remove domy-ce
    [sudo] password for user: 
    Reading package lists... Done
    Building dependency tree       
    Reading state information... Done
    Package domy-ce is not installed, so not removed
    0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

Juga diposting di: /superuser/427318/test-if-a-package-is-installed-in-apt/427898

tahoar
sumber
2
Jika Anda menginstal dan menghapus paket, selanjutnya Anda menggunakan paket dpkg-query; echo $? akan menjadi 0 juga jika paket tidak diinstal.
Pol Hallen
8

UpAndAdam menulis:

Namun Anda tidak bisa hanya mengandalkan kode pengembalian di sini untuk skrip

Dalam pengalaman saya , Anda dapat mengandalkan kode keluar dkpg.

Kode pengembalian dpkg -s adalah 0 jika paket diinstal dan 1 jika tidak, jadi solusi paling sederhana yang saya temukan adalah:

dpkg -s <pkg-name> 2>/dev/null >/dev/null || sudo apt-get -y install <pkg-name>

Bekerja dengan baik untuk saya ...

rocka84
sumber
11
Setelah apt-get remove <package>, dpkg -s <package>masih mengembalikan 0, meskipun paketnya adalahdeinstalled
ThorSummoner
7

Ini sepertinya bekerja dengan cukup baik.

$ sudo dpkg-query -l | grep <some_package_name> | wc -l
  • Entah kembali 0jika tidak diinstal atau beberapa nomor > 0jika diinstal.
sandman
sumber
8
grep | wc -ladalah antipattern. Untuk memeriksa apakah ada sesuatu, Anda hanya ingin grep -q. Untuk benar-benar menghitung kejadian (yang jarang berguna dalam skenario semacam ini), gunakan grep -c.
tripleee
@ tripleee Jadi dpkg -s zip | grep -c "Package: zip",? (menggunakan zip sebagai paket sampel)
David Tabernero M.
@Davdriver Bukan itu yang dilakukan di atas tetapi ya. Dalam skrip Anda mungkin ingin grep -q 'Package: zip'mengembalikan kode keluar yang menunjukkan apakah hasilnya ditemukan tanpa mencetak apa pun.
tripleee
ini tampaknya berfungsi dengan baik untuk paket yang dihapus juga
mehmet
4

Saya telah memilih satu berdasarkan jawaban Nultyi :

MISSING=$(dpkg --get-selections $PACKAGES 2>&1 | grep -v 'install$' | awk '{ print $6 }')
# Optional check here to skip bothering with apt-get if $MISSING is empty
sudo apt-get install $MISSING

Pada dasarnya, pesan kesalahan dari dpkg --get-selectionsjauh lebih mudah diurai daripada sebagian besar yang lain, karena tidak termasuk status seperti "deinstall". Ini juga dapat memeriksa beberapa paket secara bersamaan, sesuatu yang tidak dapat Anda lakukan hanya dengan kode kesalahan.

Penjelasan / contoh:

$ dpkg --get-selections  python3-venv python3-dev screen build-essential jq
dpkg: no packages found matching python3-venv
dpkg: no packages found matching python3-dev
screen                                          install
build-essential                                 install
dpkg: no packages found matching jq

Jadi, grep menghapus paket-paket yang terinstal dari daftar, dan awk menarik nama-nama paket dari pesan kesalahan, yang menghasilkan MISSING='python3-venv python3-dev jq', yang dapat dimasukkan secara sepele ke dalam perintah instal.

Saya tidak mengeluarkan secara membabi buta apt-get install $PACKAGESkarena seperti yang disebutkan dalam komentar, ini secara tak terduga dapat meningkatkan paket yang tidak Anda rencanakan; bukan ide yang bagus untuk proses otomatis yang diharapkan stabil.

Izkata
sumber
Saya suka solusi ini. Ringkas dan tes untuk beberapa paket sekaligus. Selain itu, Anda dapat membuat pemeriksaan opsional sesederhana[[ ! -z $MISSING ]] && sudo apt-get install $MISSING
Shenk
3

Saya telah menemukan semua solusi di atas dapat menghasilkan false positive jika suatu paket diinstal dan kemudian dihapus namun paket instalasi tetap pada sistem.

Untuk mereplikasi: Instal paket apt-get install curl
Hapus paketapt-get remove curl

Sekarang uji jawaban di atas.

Perintah berikut tampaknya mengatasi kondisi ini:
dpkg-query -W -f='${Status}\n' curl | head -n1 | awk '{print $3;}' | grep -q '^installed$'

Ini akan menghasilkan diinstal definitif atau tidak diinstal

Menandai
sumber
tidak sepenuhnya, sayangnya - hasil lain yang mungkin dalam kasus ini config-files- jadi saya pikir final | grep -q "installed"benar-benar diperlukan untuk mendapatkan status kode keluar fungsional.
tajam
buat itu| grep -q '^installed$'
tajam
3

Tampaknya saat ini apt-getmemiliki opsi --no-upgradeyang hanya melakukan apa yang diinginkan OP:

--no-upgradeJangan perbarui paket. Ketika digunakan bersama dengan instalasi, no-upgrade akan mencegah paket yang terdaftar di-upgrade jika mereka sudah diinstal.

Manpage dari https://linux.die.net/man/8/apt-get

Karena itu bisa Anda gunakan

apt-get install --no-upgrade package

dan packageakan diinstal hanya jika tidak.

Giovanni Mascellani
sumber
2
$name="rsync"

[ `which $name` ] $$ echo "$name : installed" || sudo apt-get install -y $name
Kyprio
sumber
1
Terkait, Anda harus menggunakan command -v <command>; tidak which <command>. Lihat juga Periksa apakah ada program dari skrip Bash .
jww
2

Ini akan melakukannya. apt-get installidempoten.

sudo apt-get install command
David Baucum
sumber
5
Ada skenario di mana melakukan apt-get installpaket tidak diinginkan di mana paket sudah diinstal, meskipun perintah itu sendiri idempoten. Dalam kasus saya, saya menginstal paket pada sistem jarak jauh dengan modul mentah Ansible, yang akan melaporkan sistem sebagai berubah setiap kali jika saya menjalankannya apt-get installtanpa pandang bulu. A bersyarat memecahkan masalah itu.
JBentley
1
@ Brian Bentley Itu poin bagus. Paket yang diinstal sebagai bagian dari dependensi akan ditandai sebagai diinstal secara manual, dan kemudian tidak akan dihapus ketika dependensi dihapus jika Anda ingin menginstalnya.
David Baucum
2

Menggunakan:

apt-cache policy <package_name>

Jika tidak diinstal, itu akan menunjukkan:

Installed: none

Jika tidak maka akan ditampilkan:

Installed: version
Mohammed Noureldin
sumber
1

Fitur ini sudah ada di Ubuntu dan Debian, dalam command-not-foundpaket.

camh
sumber
15
matt @ matt-ubuntu: ~ $ command-not-found command-not-found: command not found ... lol.
Matt Fletcher
1
command-not-foundadalah penolong interaktif, bukan alat untuk memastikan Anda memiliki dependensi yang Anda inginkan. Tentu saja, cara yang tepat untuk mendeklarasikan dependensi adalah dengan mengemas perangkat lunak Anda dalam paket Debian dan mengisi Depends:deklarasi dalam file paket debian/controldengan benar.
tripleee
1
apt list [packagename]

tampaknya menjadi cara paling sederhana untuk melakukannya di luar dpkg dan alat apt * lama

Erich
sumber
Ini bagus untuk pemeriksaan manual, tetapi mengeluarkan peringatan yang mengatakan bahwa apt tidak dimaksudkan untuk skrip - berbeda dengan alat apt *.
Hontvári Levente
1
which <command>
if [ $? == 1 ]; then
    <pkg-manager> -y install <command>
fi
irock.dev
sumber
1
Terkait, Anda harus menggunakan command -v <command>; tidak which <command>. Lihat juga Periksa apakah ada program dari skrip Bash .
jww
1

Saya memiliki persyaratan yang sama ketika menjalankan tes lokal, bukan di buruh pelabuhan. Pada dasarnya saya hanya ingin menginstal file deb yang ditemukan jika belum diinstal.

# If there are .deb files in the folder, then install them
if [ `ls -1 *.deb 2> /dev/null | wc -l` -gt 0 ]; then
  for file in *.deb; do
    # Only install if not already installed (non-zero exit code)
    dpkg -I ${file} | grep Package: | sed -r 's/ Package:\s+(.*)/\1/g' | xargs dpkg -s
    if [ $? != 0 ]; then
        dpkg -i ${file}
    fi;
  done;
else
  err "No .deb files found in '$PWD'"
fi

Saya kira mereka hanya masalah yang bisa saya lihat adalah tidak memeriksa nomor versi paket jadi jika file deb adalah versi yang lebih baru, maka ini tidak akan menimpa paket yang diinstal saat ini.

Craig
sumber
1

Untuk Ubuntu, apt menyediakan cara yang cukup baik untuk melakukan ini. Di bawah ini adalah contoh untuk google chrome:

apt -qq list google-chrome-stable 2>/dev/null | grep -qE "(installed|upgradeable)" || apt-get install google-chrome-stable

Saya mengarahkan output kesalahan ke nol karena apt memperingatkan untuk tidak menggunakan "cli tidak stabil". Saya menduga paket list sudah stabil jadi saya pikir tidak masalah membuang peringatan ini. -Qq membuat apt super quiet.

carlin.scott
sumber
1
ini tidak akan berfungsi dengan baik jika ada sesuatu yang "dapat ditingkatkan"
Pawel Barcik
@PawelBarcik poin bagus. Saya telah memperbarui jawaban untuk menangani situasi itu.
carlin.scott
0

Perintah ini adalah yang paling berkesan:

dpkg --get-selections <package-name>

Jika diinstal, ia akan mencetak:

<package-name> instal

Kalau tidak mencetak

Tidak ada paket yang cocok dengan <package-name>.

Ini diuji di Ubuntu 12.04.1 (Precise Pangolin).

iNulty
sumber
4
dpkg --get-selections <package-name>tidak menetapkan kode keluar ke nol ketika paket tidak ditemukan.
Lucas
0

Banyak hal yang telah diceritakan tetapi bagi saya cara paling sederhana adalah:

dpkg -l | grep packagename
freedev
sumber
0

Di Bash:

PKG="emacs"
dpkg-query -l $PKG > /dev/null || sudo apt install $PKG

Perhatikan bahwa Anda dapat memiliki string dengan beberapa paket di PKG.

daruma
sumber
0

Saya menggunakan cara berikut:

which mySQL 2>&1|tee 1> /dev/null
  if [[ "$?" == 0 ]]; then
                echo -e "\e[42m MySQL already installed. Moving on...\e[0m"
        else
        sudo apt-get install -y mysql-server
                if [[ "$?" == 0 ]]; then
                        echo -e "\e[42mMy SQL installed\e[0m"
                else
                        echo -e "\e[42Installation failed\e[0m"
                fi
        fi
Nitish Jadia
sumber