วิธีทำให้ผู้จัดการแพคเกจรอถ้าอินสแตนซ์อื่นของ APT กำลังทำงานอยู่?


50

ฉันเคยเห็นซอฟต์แวร์มากมายเช่น Update Manager และ Synaptic Package Manager พวกเขารอว่าโปรแกรมอื่นกำลังใช้งาน/var/lib/dpkg/lockและถูกล็อคอยู่หรือไม่ เราจะทำสิ่งนี้ผ่านเทอร์มินัลได้อย่างไร ฉันเห็นapt-getคู่มือ แต่ไม่พบว่ามีประโยชน์อะไร


คุณสามารถทำคำสั่ง apt-get ได้หลายคำสั่ง กดsudo apt-get install packagename && sudo apt-get updateไลค์และมันจะเกิดขึ้นอัตโนมัติหลังจากกันและกัน
อัลวาร์

1
สิ่งนี้ไม่ได้ทำอย่างนั้นsudo apt-get install packagename1 packagename2 packagename3 หรือ
Rinzwind

(ดูunix.stackexchange.com/questions/463498/ …ถ้าคุณอยู่ในกรณีพิเศษที่คุณกำลังรอเวลาบู๊ตให้เสร็จใน Ubuntu 18.04 ขึ้นไป)
Anon

คำตอบ:


35

คุณสามารถใช้คำสั่งไปยังคิวค่างานผู้จัดการแพคเกจโดยการสื่อสารกับ aptdaemon แทนการใช้ apt-get โดยตรงaptdconไอคอน Manpage

ดังนั้นโดยทั่วไปคุณสามารถทำsudo aptdcon --install chromium-browserอะไรก็ได้และในขณะที่คำสั่งนั้นกำลังรันอยู่คุณสามารถรันได้อีกครั้ง แต่การติดตั้งแพ็กเกจที่แตกต่างกันและ apt-daemon จะคิวพวกมันขึ้นแทนที่จะทำการคลาดเคลื่อน

สิ่งนี้มีประโยชน์อย่างยิ่งหากคุณทำการอัพเกรดที่ยาวนานหรือบางอย่างและต้องการติดตั้งแพ็กเกจต่อไปหรือถ้าคุณเขียนสคริปต์บางอย่างด้วยกันและต้องการให้แน่ใจว่าการติดตั้งสิ่งต่าง ๆ จะเชื่อถือได้มากขึ้น


4
สามารถaptdconเรียกใช้เช่นนั้นยอมรับการแจ้งใด ๆ เช่นapt-get -yนั้น?
Noki

4
yes | aptdcon --hide-terminal --install "package"จำเป็นต้องซ่อน Terminal มิฉะนั้นการวางท่อyesจะทำให้เกิดปัญหา
whitehat101

1
aptdconปัญหากับคำตอบนี้ก็คือว่ามันต้องมีการติดตั้ง ฉันกำลังทำงานกับสคริปต์บู๊ตสแตรปที่ทำการตั้งค่าเริ่มต้นของ VPS ซึ่งกระบวนการพื้นหลังกำลังทำการตั้งค่าเริ่มต้นด้วยเช่นกัน ฉันไม่สามารถติดตั้งได้aptdconจนกว่าฉันจะแก้ปัญหาได้
ชื่อปลอม

2
@FakeName สำหรับการกำหนดค่าเซิร์ฟเวอร์เริ่มต้นคุณอาจต้องการใช้ cloud-init: cloudinit.readthedocs.io/en/latest
Jorge Castro

1
แพ็คเกจอะไรอยู่aptdcon?
ctrl-alt-delor

45

คุณสามารถapt-getเรียนรู้ที่จะรอว่าตัวจัดการซอฟต์แวร์อื่นกำลังทำงานอยู่หรือไม่ สิ่งที่คล้ายกับพฤติกรรมจากการส่งหน้าจอถัดไป:

ป้อนคำอธิบายรูปภาพที่นี่

ฉันทำมันได้อย่างไร

ฉันสร้างสคริปต์ใหม่ที่เรียกว่าapt-get(wrapper for apt-get) ใน/usr/local/sbinไดเรกทอรีที่มีรหัส bash ต่อไปนี้ภายใน:

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

อย่าลืมที่จะทำให้มันปฏิบัติการได้:

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

ก่อนที่จะทำการทดสอบตรวจสอบว่าทุกอย่างเรียบร้อยดี การส่งออกของคำสั่งที่ควรจะเป็นในขณะนี้which apt-get /usr/local/sbin/apt-getเหตุผลก็คือ: โดยค่าเริ่มต้น/usr/local/sbinไดเรกทอรีวางไว้ก่อนไดเรกทอรีในผู้ใช้หรือราก/usr/binPATH


นั่นเป็นคำถามที่ตรงไปตรงมาจริงๆ ขอบคุณ :)
rɑːdʒɑ

2
apt-get สคริปต์ของคุณจัดการอินสแตนซ์ที่ซ้อนกันอย่างไร เช่นก่อนที่มันจะเสร็จฉันเปิดอีก 5 ฉลาด - รับ?
Braiam

@Braiam ขอแสดงความนับถือฉันไม่รู้ ฉันไม่ใช่ผู้ทดสอบที่ดี คุณทดสอบหรือไม่ หากปัญหาปรากฏขึ้นสคริปต์สามารถปรับปรุงได้โดยการสร้างการล็อกใหม่ด้วยการประทับเวลาเมื่ออินสแตนซ์ใหม่ของสคริปต์เริ่มต้นขึ้น (เพียงตัวอย่าง - ยังมีวิธีอื่น ๆ อีกมากมาย)
Radu Rădeanu

ว้าว! พูดเก่ง ทำงานเหมือนมีเสน่ห์กับทุกสิ่งที่ฉันเคยทำมาจนถึงตอนนี้! ยกนิ้วสองนิ้ว ... นี่ควรเป็นส่วนหนึ่งของแพ็คเกจ: D
Eric

2
มันสมบูรณ์แบบ! ฉันมีปัญหาที่ฉันใช้ AWS cloudinit เพื่อติดตั้งแพ็กเกจบนเซิร์ฟเวอร์ใหม่ แต่ Ubuntu ทำบางอย่างaptในการบู๊ตดังนั้นdpkgคำสั่งของฉันจึงล้มเหลวเนื่องจากล็อค dpkg db ฉันใส่หนึ่งซับใน clouddit ของฉัน userdata: while fuser /var/lib/dpkg/lock >/dev/null 2>&1; do sleep 1; done; dpkg -i package.debและมันใช้งานได้ดี
Volodymyr Smotesko

20

นอกเหนือจากที่เห็นได้ชัดคุณอาจจะมองหา&& aptdconเครื่องมือนี้สามารถตรวจจับอินสแตนซ์อื่น ๆ ของ apt และรอให้เสร็จสิ้น:

sudo aptdcon --safe-upgrade
[/] 11% กำลังรอให้ผู้จัดการซอฟต์แวร์คนอื่นเลิกออกจากการรอความถนัด

(ฉันใช้ความสามารถที่อื่น)

ข้อดีของเครื่องมือนี้คือคุณสามารถเก็บหลาย ๆ การกระทำติดต่อกันโดยไม่ต้องกังวลว่าคุณจะทำอะไรต่อไป aptdconเหมาะสำหรับสคริปต์แบบอัตโนมัติและการติดตั้ง GUI เนื่องจากคุณสามารถอนุญาตให้เครื่องมือทำงานในพื้นหลังเพื่อไม่ให้บล็อกส่วนหน้าของคุณ

การดำเนินการที่รองรับaptdconคือ:

  • --refresh, -c: apt-get updateนี่คือเทียบเท่ากับ มันอัพเดตรายชื่อแพ็คเกจของคุณ
  • --install, --remove, --upgrade, ,--purge --downgradeแต่ละคนทำตามที่ชื่อพูด ชื่อของแพคเกจมีผลบังคับใช้ -i, -r, -u, -pเหล่านี้เป็นตัวเลือกที่สั้นสำหรับทุกคนยกเว้นการปรับลดที่ไม่ได้มีอย่างใดอย่างหนึ่ง
  • --safe-upgrade, --full-upgradeมีลูกน้องไปapt-get's upgrade/ dist-upgradeและaptitude' safe-upgrades full-upgrade/ สิ่งเหล่านี้ไม่ต้องการพารามิเตอร์
  • มีการทำงานอื่น ๆ หลายประการซึ่งสามารถพบได้ในคู่มือ แต่สิ่งเหล่านี้เป็นสิ่งที่ผู้ใช้สนใจaptdมากที่สุด มีตัวเลือกที่ทับซ้อนกับสิ่งที่เป็นapt-key, apt-cache, dpkgทำ

apt-getตัวเองไม่สนับสนุนวิธีการดังกล่าว (เพื่อรออินสแตนซ์อื่น ๆ ของ apt) ดังนั้นจึงaptdconเป็นทางออกที่ต้องการสำหรับผู้จัดการแพ็คเกจของ GUI: USC ใช้aptdเป็นแบ็คเอนด์เช่นเดียวกับ Synaptic โซลูชันอื่น ๆ คือpackagekitแต่มันไม่รองรับฟังก์ชั่นที่คุณกำลังมองหา (ยัง)


1
aptdcon --install /path/to/pgk.debทำงานได้เหมือนdpkg -iกันแม้ว่าฉันจะไม่สามารถค้นหาสิ่งนี้ได้กล่าวถึงอย่างชัดเจนในคู่มือ
whitehat101

ฉันสามารถใช้สิ่งนี้ในสคริปต์หลังการติดตั้งในแพ็คเกจหรือไม่?
Nelson Teixeira

@NelsonTeixeira ทำไมคุณต้องใช้สิ่งนี้ในสคริปต์ ppst-install หากโพสต์ติดตั้งจะถูกดำเนินการอย่างเห็นได้ชัดกำลังทำงาน
Braiam

ฉันต้องการทำให้การติดตั้งภายหลังติดตั้งแพ็คเกจพิเศษบางอย่างที่ไม่ได้อยู่ในที่เก็บ เป็นไปได้ไหม ฉันจะรวมไว้ในแพ็คเกจแล้วสคริปต์จะติดตั้งหลังจากการติดตั้งเสร็จสิ้น
เนลสัน Teixeira

@NelsonTeixeira อีกครั้งทำไมมันจำเป็น? สคริปต์หลังการติดตั้งจะทำงานเฉพาะเมื่อมีการติดตั้งแพ็คเกจ ฉันแนะนำให้คุณถามคำถามแทนและอธิบายกรณีของคุณพร้อมรายละเอียดเพิ่มเติม
Braiam

18

วิธีการง่าย ๆ น่าจะเป็นสคริปต์ที่รอให้ล็อคไม่เปิด ลองเรียกมันwaitforaptและติดมันใน/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

sudo waitforapt && sudo apt-get install whateverจากนั้นเรียกเพียง คุณสามารถเพิ่มข้อยกเว้นsudoersเพื่ออนุญาตให้คุณเรียกใช้โดยไม่ต้องใช้รหัสผ่าน (คุณจะต้องใช้รหัสผ่านapt-getเพื่อให้ได้รับประโยชน์ที่ดี)

น่าเสียดายที่นี่ไม่ได้จัดคิว เนื่องจากการทำงานบางอย่างของ apt นั้นเป็นแบบโต้ตอบ ("คุณแน่ใจหรือไม่ว่าคุณต้องการลบแพ็คเกจเหล่านั้นทั้งหมด!!") ฉันไม่เห็นวิธีที่ดีในเรื่องนี้ ...


อาจ-yจะถือว่าใช่สำหรับการดำเนินการทั้งหมดหรือไม่
Braiam

ขอขอบคุณ. ฉันคิดว่าฉันสามารถใช้งานได้ดีกว่าถ้าฉันใช้นามแฝงช่วย
rɑːdʒɑ

3
ไม่แน่ใจว่า-yเป็นที่พึงปรารถนา
Oli

1
ผมไม่คิดว่าคุณต้องการที่จะห่อในsudo fuser [[ $(...) ]]มันจะส่งคืนรหัสการออกเป็นศูนย์เมื่อมีการเข้าถึงไฟล์เพื่อให้เพียงพอ
kiri

4
ฉันพบวิธีแก้ไขปัญหาต่อไปนี้ให้สมบูรณ์ยิ่งขึ้นเนื่องจากมีการล็อคหลายอย่างที่เกี่ยวข้องเมื่อทำงานกับ 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

คุณสามารถใช้เทคนิคการสำรวจความคิดเห็น:

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

ดีกว่าที่จะใช้inotify
ctrl-alt-delor

3

ฉันทำสคริปต์ซึ่งทำสิ่งนี้:

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

/usr/local/sbin/apt-getบันทึกข้างต้นลงใน apt-getจะรอถ้าอินสแตนซ์อื่นกำลังทำงานอยู่

หรือมิฉะนั้นให้บันทึกเป็น/usr/local/sbin/apt-waitตัวอย่างการใช้:

apt-wait && aptitude

ซึ่งจะทำงานaptitudeหลังจากกระบวนการปัจจุบันที่ถือล็อคได้ออก

ตัวอย่างการเรียกใช้:

  1. ก่อนapt-getคำสั่งจะถูกเรียกใช้ตัวอย่างเช่น:

    $ sudo apt-get remove some_package
    
  2. จากนั้นในเทอร์มินัลอื่นรันคำสั่งอื่น:

    $ sudo apt-get install some_other_package
    

    มันจะรอให้คำสั่งแรกให้เสร็จสิ้นจากนั้นเรียกใช้ ผลผลิตขณะรอ:

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

1
ดีกว่าที่จะใช้inotify
ctrl-alt-delor

3

น่าเสียดายที่ฟิวเซอร์ไม่ได้ทำอะไรมากมายสำหรับคุณเมื่อคุณใช้งานในคอนเทนเนอร์เนมสเปซที่ไม่มีผู้ด้อยโอกาสเช่น lxc

นอกจากนี้ยังไม่มีการติดตั้ง aptdcon ตามค่าเริ่มต้น (อย่างน้อย 18.04) และทำให้งานของคุณอยู่ในคิวเพื่อให้คุณเสียการจัดลำดับ นี่ไม่สามารถเอาชนะได้ แต่หมายความว่าระบบอัตโนมัติของคุณจำเป็นต้องมีวิธีในการหลีกเลี่ยงข้อผิดพลาดในการติดตั้ง aptdcon และคุณต้องมีการวนรอบรอสำหรับสิ่งที่คุณต้องการทำให้เป็นอนุกรมหลังจากติดตั้งแพคเกจผ่าน aptdcon นอกเสียจากว่าจะมีการตั้งค่าสถานะสำหรับบางอย่างแล้ว

งานอะไรแห่กัน สิ่งนี้ควรทำงานเหนือ NFS ฯลฯ เนื่องจากใช้การล็อกระบบไฟล์ในลักษณะเดียวกับที่ทำเฉพาะกับพารามิเตอร์ -w วินาทีเท่านั้นที่จะรอการล็อกของคุณแทนที่จะโยนข้อผิดพลาด

ดังนั้นตามโมเดล wrapper เพิ่มสิ่งนี้เป็น apt-get in / usr / local / bin / และแชร์

สิ่งนี้ยังมีประโยชน์ในการ จำกัด IO โดยไม่อนุญาตให้มีการขนานบน apt ดังนั้นคุณสามารถปล่อยให้ cron trigger อัพเดทในเวลาเที่ยงคืนได้ทุกที่โดยไม่ต้องชนดิสก์

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

คำขอคุณสมบัติที่ดีและเรียบง่ายสำหรับ apt-get จะเป็นแฟล็ก -w เพื่อสลับไปยังการล็อคการบล็อก / รอ


ฉลาดใช้ fcntl ไม่ใช่แห่ดังนั้นสิ่งนี้จะไม่ทำงาน askubuntu.com/questions/1077215/…
Andy

วิธีนี้ใช้งานได้ดีและเป็นตัวเลือกที่ดีกว่าการใช้fuserตามที่แสดงในคำตอบมากมายเนื่องจากfuserยังมีแนวโน้มที่จะแย่งชิงระหว่างการดูการล็อกและกระบวนการเป้าหมายการล็อกการล็อกอีกครั้ง ด้วยflockการล็อคจะได้รับแล้วส่งผ่านไปยังกระบวนการเป้าหมายดังนั้นจึงไม่มีเวลาสำหรับการสูญเสียการล็อคในระหว่างนี้
jrudolph

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.