Bagaimana membuat manajer paket menunggu jika instance APT lain berjalan?


50

Saya telah melihat banyak software seperti Update Manager dan Synaptic Package Manager, mereka menunggu jika beberapa program lain menggunakan /var/lib/dpkg/lockdan terkunci. Bagaimana kita bisa melakukan ini melalui Terminal? Saya melihat apt-getmanual tetapi tidak menemukan sesuatu yang bermanfaat.


Anda bisa melakukan beberapa perintah apt-get. Suka sudo apt-get install packagename && sudo apt-get updatedan mereka akan terjadi secara otomatis setelah satu sama lain.
Alvar

1
Apakah ini tidak melakukan itu sudo apt-get install packagename1 packagename2 packagename3 :?
Rinzwind

(Lihat unix.stackexchange.com/questions/463498/... jika Anda berada dalam kasus khusus di mana Anda mencoba menunggu waktu boot untuk selesai di Ubuntu 18.04 dan lebih tinggi)
Anon

Jawaban:


35

Anda dapat menggunakan yang aptdconperintahIkon halaman manual untuk mengantri tugas manajer paket dengan berkomunikasi dengan aptdaemon daripada menggunakan apt-get langsung.

Jadi pada dasarnya Anda hanya dapat melakukan sudo aptdcon --install chromium-browseratau apa pun dan saat perintah itu berjalan Anda dapat menjalankannya lagi tetapi menginstal paket yang berbeda dan apt-daemon hanya akan mengantri mereka alih-alih kesalahan keluar.

Ini sangat berguna jika Anda melakukan upgrade yang lama atau sesuatu dan ingin terus menginstal paket atau jika Anda membuat skrip sesuatu bersama-sama dan ingin memastikan bahwa menginstal sesuatu akan lebih dapat diandalkan.


4
Dapat aptdcondijalankan sedemikian rupa sehingga menerima konfirmasi apa pun seperti apt-get -yhalnya?
Noki

4
yes | aptdcon --hide-terminal --install "package"Hide Terminal diperlukan, jika tidak perpipaan yesakan menyebabkan masalah.
whitehat101

1
Masalah dengan jawaban ini adalah itu membutuhkan instalasi aptdcon. Saya sedang mengerjakan skrip bootstrap yang melakukan pengaturan awal VPS, di mana proses latar belakang melakukan beberapa pengaturan awal juga. Saya tidak dapat menginstal aptdconsampai saya dapat bekerja di sekitar kunci.
Nama Palsu

2
@FakeName untuk konfigurasi server awal, Anda mungkin ingin menggunakan cloud-init: cloudinit.readthedocs.io/en/latest
Jorge Castro

1
paket apa yang ada aptdcondi dalam?
ctrl-alt-delor

45

Anda dapat membuat apt-getbelajar menunggu jika pengelola perangkat lunak lain berjalan. Sesuatu yang mirip dengan perilaku dari layar berikutnya:

masukkan deskripsi gambar di sini

Bagaimana saya membuatnya?

Saya membuat skrip baru bernama apt-get(wrapper for apt-get) dalam /usr/local/sbindirektori dengan kode bash berikut di dalamnya:

#!/bin/bash

i=0
tput sc
while fuser /var/lib/dpkg/lock >/dev/null 2>&1 ; do
    case $(($i % 4)) in
        0 ) j="-" ;;
        1 ) j="\\" ;;
        2 ) j="|" ;;
        3 ) j="/" ;;
    esac
    tput rc
    echo -en "\r[$j] Waiting for other software managers to finish..." 
    sleep 0.5
    ((i=i+1))
done 

/usr/bin/apt-get "$@"

Jangan lupa untuk membuatnya dieksekusi:

sudo chmod +x /usr/local/sbin/apt-get

Sebelum menguji, periksa apakah semuanya baik-baik saja. Output dari which apt-getperintah harus sekarang /usr/local/sbin/apt-get. Alasannya adalah: secara default, /usr/local/sbindirektori ditempatkan sebelum /usr/bindirektori di pengguna atau root PATH.


itu benar-benar hit langsung ke pertanyaan saya. thanks :)
rɑːdʒɑ

2
Bagaimana skrip Anda mengelola instance apt-get yang disusun? Seperti, sebelum selesai saya meluncurkan 5 apt-get lainnya?
Braiam

@Braiam Hormat saya, saya tidak tahu; Saya bukan penguji yang baik. Apakah Anda mengujinya? Jika masalah muncul, skrip dapat ditingkatkan dengan membuat kunci baru dengan stempel waktu saat instance skrip baru dimulai (hanya sebuah contoh - ada juga banyak cara lain).
Radu Rădeanu

Wow! fasih. bekerja seperti pesona dengan semua yang saya lakukan sejauh ini! Dua jempol ... ini seharusnya hanya menjadi bagian dari paket: D
Eric

2
Itu sempurna! Saya mempunyai masalah di mana saya menggunakan AWS cloudinit untuk menginstal paket pada server baru, tetapi Ubuntu melakukan beberapa apthal saat boot, jadi dpkgperintah saya gagal karena terkunci dpkg db. Saya telah menempatkan satu-liner ini di data cloudinit user saya: while fuser /var/lib/dpkg/lock >/dev/null 2>&1; do sleep 1; done; dpkg -i package.debdan ini berfungsi dengan baik.
Volodymyr Smotesko

20

Terlepas dari yang sudah jelas &&, Anda mungkin mencari aptdcon. Alat ini dapat mendeteksi instance apt lainnya dan menunggu hingga selesai:

sudo aptdcon --safe-upgrade
[/] 11% Menunggu manajer perangkat lunak lain berhenti Menunggu bakat

(Saya menjalankan bakat di tempat lain)

Keuntungan dari alat ini adalah Anda dapat menyimpan beberapa tindakan secara berurutan tanpa khawatir dengan apa yang akan Anda lakukan selanjutnya. aptdconsangat ideal untuk skrip yang tidak dijaga, dan pemasangan GUI, karena Anda dapat membiarkan alat berjalan di latar belakang agar tidak memblokir frontend Anda.

Operasi yang didukung oleh aptdconadalah:

  • --refresh, -c: Ini setara dengan apt-get update. Ini memperbarui daftar paket Anda.
  • --install, --remove, --upgrade, --purge, --downgrade. Masing-masing dari mereka melakukan seperti namanya. Nama paket itu wajib. -i, -r, -u, -p: Ini adalah pilihan singkat untuk semua kecuali downgrade, yang tidak memiliki satu.
  • --safe-upgrade, --full-upgradeAdalah rekan-rekan untuk apt-get's upgrade/ dist-upgradedan aptitude' s safe-upgrade/ full-upgrade. Ini tidak perlu parameter.
  • Ada beberapa operasi lain, yang dapat ditemukan di manual. Tapi, ini adalah yang paling banyak digunakan oleh pengguna yang tertarik aptd. Ada pilihan yang tumpang tindih dengan apa apt-key, apt-cache, dpkglakukan.

apt-getitu sendiri tidak mendukung metode seperti itu (untuk menunggu contoh apt lainnya), jadi aptdconadalah solusi yang lebih disukai untuk manajer paket GUI: USC menggunakan aptdsebagai back-end, sama seperti Synaptic. Solusi lain adalah packagekit, tetapi tidak mendukung fungsi yang Anda cari (belum).


1
aptdcon --install /path/to/pgk.debBerfungsi seperti dpkg -i, meskipun saya tidak dapat menemukan ini secara eksplisit disebutkan dalam manual.
whitehat101

Bisakah saya menggunakan ini dalam skrip post-instal dalam sebuah paket?
Nelson Teixeira

@NelsonTeixeira mengapa Anda menggunakan ini di skrip install ppst? Jika post-install dieksekusi jelas apt sedang berjalan.
Braiam

Saya ingin membuat postinstall menginstal beberapa paket khusus yang tidak ada dalam repositori. Apakah ini mungkin? Saya akan memasukkan mereka dalam paket dan kemudian skrip akan menginstalnya setelah instalasi selesai.
Nelson Teixeira

@NelsonTeixeira lagi, mengapa itu perlu? Script post-install hanya berjalan ketika ada instalasi paket. Saya sarankan Anda untuk mengajukan pertanyaan dan menjelaskan kasus Anda dengan lebih detail.
Braiam

18

Pendekatan yang sangat sederhana adalah skrip yang menunggu kunci tidak terbuka. Sebut saja waitforaptdan masukkan /usr/local/bin:

#!/bin/sh

while sudo fuser /var/{lib/{dpkg,apt/lists},cache/apt/archives}/lock >/dev/null 2>&1; do
   sleep 1
done

Maka jalankan saja sudo waitforapt && sudo apt-get install whatever. Anda dapat menambahkan pengecualian ke dalam sudoersuntuk memungkinkan Anda menjalankannya tanpa perlu kata sandi (Anda akan membutuhkannya untuk apt-getitu sehingga tidak ada keuntungan besar).

Sayangnya ini tidak mengantri. Mengingat beberapa operasi apt bersifat interaktif ("Apakah Anda yakin ingin menghapus semua paket itu ?!"), saya tidak dapat melihat cara yang baik untuk mengatasi ini ...


mungkin -yuntuk menganggap ya untuk semua operasi?
Braiam

Terima kasih. Saya pikir saya bisa menggunakannya lebih baik jika saya menggunakan bantuan alias.
rɑːdʒɑ

3
-yMeskipun tidak yakin diinginkan.
Oli

1
Saya tidak berpikir Anda ingin untuk membungkus sudo fuserdi [[ $(...) ]]. Ini mengembalikan kode keluar nol ketika file sedang diakses sehingga harus memadai.
kiri

4
Saya menemukan solusi berikut menjadi lebih lengkap, karena ada beberapa kunci yang terlibat ketika bekerja dengan apt-get: while sudo fuser /var/lib/dpkg/lock /var/lib/apt/lists/lock /var/cache/apt/archives/lock >/dev/null 2>&1; do echo 'Waiting for release of dpkg/apt locks'; sleep 5; done; sudo apt-get -yy update
Manuel Kießling

3

Anda bisa menggunakan teknik polling:

$ time (while ps -opid= -C apt-get > /dev/null; do sleep 1; done); \
  apt-get -y install some-other-package

lebih baik digunakaninotify
ctrl-alt-delor

3

Saya membuat skrip yang melakukan ini:

#!/bin/bash

# File path to watch
LOCK_FILE='/var/lib/dpkg/lock'

# tput escape codes
cr="$(tput cr)"
clr_end="$(tput el)"
up_line="$(tput cuu 1)"

CLEAN(){
    # Cleans the last two lines of terminal output,
    # returns the cursor to the start of the first line
    # and exits with the specified value if not False

    echo -n "$cr$clr_end"
    echo
    echo -n "$cr$clr_end$up_line"
    if [[ ! "$1" == "False" ]]; then
        exit $1
    fi
}

_get_cmdline(){
    # Takes the LOCKED variable, expected to be output from `lsof`,
    # then gets the PID and command line from `/proc/$pid/cmdline`.
    #
    # It sets `$open_program` to a user friendly string of the above.

    pid="${LOCKED#p}"
    pid=`echo $pid | sed 's/[\n\r ].*//'`
    cmdline=()
    while IFS= read -d '' -r arg; do
        cmdline+=("$arg")
    done < "/proc/${pid}/cmdline"
    open_program="$pid : ${cmdline[@]}"
}

# Default starting value
i=0

# Checks if the file is locked, writing output to $FUSER
while LOCKED="$(lsof -F p "$LOCK_FILE" 2>/dev/null)" ; do
    # This will be true if it isn't the first run
    if [[ "$i" != 0 ]]; then
        case $(($i % 4)) in
            0 ) s='-'
                i=4
                _get_cmdline # Re-checks the command line each 4th iteration
            ;;
            1 ) s=\\ ;;
            2 ) s='|' ;;
            3 ) s='/' ;;
        esac
    else
        # Traps to clean up the printed text and cursor position
        trap "CLEAN False; trap - SIGINT ; kill -SIGINT $$" SIGINT
        trap 'CLEAN $((128+15))' SIGTERM
        trap 'CLEAN $((128+1))' SIGHUP
        trap 'CLEAN $((128+3))' SIGQUIT

        # Default starting character
        s='-'

        _get_cmdline
        echo -n "$save_cur"
    fi
    # Prints the 2nd line first so the cursor is at the end of the 1st line (looks nicer)
    echo
    echo -n "$cr$clr_end$open_program"
    echo -n "$up_line$res_cur$cr$clr_end[$s] Waiting for other package managers to finish..."
    #echo -en "$cr$clr_end[$s] Waiting for other package managers to finish..."
    #echo -en "\n$cr$clr_end$open_program$cr$up_line"
    ((i++))
    sleep 0.025
done

CLEAN False

# This allows saving the script under a different name (e.g. `apt-wait`)
# and running it. It only imitates `apt-get` if it was launched as such
if [[ "${0##*/}" == 'apt-get' ]]; then
    exec /usr/bin/apt-get "$@"
    exit $?
fi

Simpan di atas ke dalam /usr/local/sbin/apt-get. apt-getkemudian akan menunggu jika instance lain sudah berjalan.

Atau, simpan sebagai /usr/local/sbin/apt-wait, contoh penggunaan:

apt-wait && aptitude

yang akan berjalan aptitudesetelah proses saat memegang kunci telah keluar.

Contoh dijalankan:

  1. Pertama, apt-getperintah dijalankan, misalnya:

    $ sudo apt-get remove some_package
    
  2. Kemudian, di terminal lain, perintah lain dijalankan:

    $ sudo apt-get install some_other_package
    

    Ini akan menunggu perintah pertama selesai kemudian jalankan. Output sambil menunggu:

    [/] Waiting for other package managers to finish...
          28223 : /usr/bin/apt-get remove some_package
    

1
lebih baik digunakaninotify
ctrl-alt-delor

3

Sayangnya fuser tidak banyak membantu Anda ketika Anda menjalankan berbagai wadah namespace yang tidak terjangkau seperti lxc.

Juga, aptdcon tidak diinstal secara default (setidaknya pada 18,04) dan latar belakang tugas Anda dalam antrian sehingga Anda kehilangan serialisasi. Ini tidak dapat diatasi, tetapi itu berarti otomasi Anda perlu memiliki beberapa cara untuk menghindari kesalahan kawanan di apt ketika menginstal aptdcon, dan Anda harus memiliki semacam loop menunggu untuk apa pun yang Anda butuhkan untuk membuat serialisasi setelah menginstal paket melalui aptdcon kecuali sudah ada semacam bendera untuk itu.

Apa yang berhasil adalah kawanan. Ini juga harus bekerja pada NFS dll karena menggunakan penguncian sistem file dengan cara yang sama dengan apt, hanya dengan parameter -w detik ia akan menunggu di kunci Anda alih-alih melemparkan kesalahan.

Jadi mengikuti model wrapper, tambahkan ini sebagai apt-get in / usr / local / bin / dan bagikan.

Ini juga memiliki manfaat membatasi IO dengan tidak mengizinkan paralelisme pada apt sehingga Anda dapat membiarkan cron memicu pembaruan di tengah malam di mana-mana tanpa mengalahkan disk.

#!/bin/bash
exec /usr/bin/flock -w 900 -F --verbose /var/cache/apt/archives/lock /usr/bin/apt-get $@  

Permintaan fitur yang sangat bagus dan sederhana untuk apt-get akan menjadi flag -w untuk beralih ke pemblokiran / kunci tunggu.


apt menggunakan fcntl, bukan flock, jadi ini tidak akan berfungsi. askubuntu.com/questions/1077215/…
Andy

Ini berfungsi dengan baik dan merupakan pilihan yang lebih baik daripada menggunakan fuserseperti yang ditunjukkan dalam banyak jawaban karena fusermasih rentan terhadap kondisi balapan antara menonton kunci dan proses target meraih kunci lagi. Dengan flockkunci diperoleh dan kemudian diteruskan ke proses target sehingga tidak ada waktu untuk kehilangan kunci sementara itu.
jrudolph

1

Satu kalimat berdasarkan jawaban Oli :

while sudo fuser /var/{lib/{dpkg,apt/lists},cache/apt/archives}/lock >/dev/null 2>&1; do sleep 1; done
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.