¿Cómo hacer que un administrador de paquetes espere si se está ejecutando otra instancia de APT?

50

He visto muchos softwares como Update Manager y Synaptic Package Manager, esperan si algún otro programa está usando /var/lib/dpkg/locky está bloqueado. ¿Cómo podemos hacer esto a través de la Terminal? Vi apt-getel manual pero no encontré nada útil.

Piyush
fuente
bueno, puedes hacer varios comandos apt-get. Me gusta sudo apt-get install packagename && sudo apt-get updatey sucederán automáticamente uno después del otro.
Alvar
1
¿Esto no hace eso sudo apt-get install packagename1 packagename2 packagename3 ?
Rinzwind el
(Consulte unix.stackexchange.com/questions/463498/… si se encuentra en el caso especial en el que está tratando de esperar a que el tiempo de arranque termine en Ubuntu 18.04 en adelante)
Anon

Respuestas:

35

Puede usar el aptdconcomandoIcono de página de manual para poner en cola las tareas del administrador de paquetes comunicándose con aptdaemon en lugar de usar apt-get directamente.

Básicamente, puede hacer sudo aptdcon --install chromium-browserlo que sea y mientras se ejecuta ese comando, puede ejecutarlo nuevamente, pero instale diferentes paquetes y apt-daemon simplemente los pondrá en cola en lugar de generar errores.

Esto es especialmente útil si está realizando una actualización larga o algo así y desea seguir instalando paquetes o si está creando una secuencia de comandos juntos y quiere asegurarse de que la instalación sea más confiable.

Jorge Castro
fuente
44
¿Se aptdconpuede ejecutar de modo que acepte cualquier mensaje como lo apt-get -yhace?
Noki
44
yes | aptdcon --hide-terminal --install "package"Hide Terminal es necesario, de lo contrario, las tuberías yescausarán problemas.
whitehat101
1
El problema con esta respuesta es que requiere instalación aptdcon. Estoy trabajando en un script de arranque que realiza la configuración inicial de un VPS, donde un proceso en segundo plano también está haciendo una configuración inicial. No puedo instalar aptdconhasta que pueda evitar la cerradura.
Nombre falso
2
@FakeName para la configuración inicial del servidor que probablemente quiera usar cloud-init: cloudinit.readthedocs.io/en/latest
Jorge Castro
1
qué paquete es aptdconen?
ctrl-alt-delor
45

Puede apt-getaprender a esperar si se está ejecutando otro administrador de software. Algo similar con el comportamiento del próximo elenco de pantalla:

ingrese la descripción de la imagen aquí

¿Cómo lo hice?

Creo un nuevo script llamado apt-get(wrapper for apt-get) en el /usr/local/sbindirectorio con el siguiente código bash dentro:

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

No olvides hacerlo ejecutable:

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

Antes de realizar la prueba, verifique si todo está bien. La salida del which apt-getcomando debería ser ahora /usr/local/sbin/apt-get. El motivo es: de manera predeterminada, el /usr/local/sbindirectorio se coloca antes del /usr/bindirectorio en usuario o raíz PATH.

Radu Rădeanu
fuente
Eso es realmente un golpe directo a mi pregunta. gracias :)
r 10dʒɑ
2
¿Cómo gestiona tu script las instancias apiladas de apt-get? Como, antes de que termine, ¿lanzo 5 apt-get más?
Braiam
@Braiam Sinceramente, no lo sé; No soy un buen probador. ¿Lo probaste? Si aparecen problemas, el script se puede mejorar creando un nuevo bloqueo con marca de tiempo cuando se inicia una nueva instancia del script (solo un ejemplo, también hay muchas otras formas).
Radu Rădeanu
¡Guauu! elocuente. ¡funciona de maravilla con todo lo que le he arrojado hasta ahora! Dos aprobado ... esto debería ser parte del paquete: D
Eric
2
¡Eso es perfecto! He tenido un problema al usar AWS cloudinit para instalar paquetes en un nuevo servidor, pero Ubuntu hace algunas aptcosas en el arranque, por lo que mi dpkgcomando falló debido al bloqueo de dpkg db. He incluido esta línea en mis datos de usuario de cloudinit: while fuser /var/lib/dpkg/lock >/dev/null 2>&1; do sleep 1; done; dpkg -i package.deby funciona muy bien.
Volodymyr Smotesko
20

Aparte de lo obvio &&, puede estar buscando aptdcon. Esta herramienta puede detectar otras instancias de apt y esperar a que finalicen:

sudo aptdcon --safe-upgrade
[/] 11% Esperando a que otros administradores de software salgan Esperando aptitud

(Estoy corriendo aptitud en otro lugar)

La ventaja de esta herramienta es que puede almacenar varias acciones consecutivas sin preocuparse de lo que hará a continuación. aptdcones ideal para scripts desatendidos e instalación de GUI, ya que puede permitir que la herramienta se ejecute en segundo plano para no bloquear su interfaz.

Las operaciones soportadas por aptdconson:

  • --refresh, -c: Esto es equivalente a apt-get update. Actualiza tu lista de paquetes.
  • --install` --remove` --upgrade` --purge` --downgrade. Cada uno de ellos hace lo que dicen sus nombres. El nombre del paquete (s) es obligatorio. -i, -r, -u, -p: Estas son las opciones cortos para todos excepto rebaja, que no tiene uno.
  • --safe-upgrade, --full-upgradeson las contrapartes de apt-get's upgrade/ dist-upgradey aptitude' s safe-upgrade/ full-upgrade. Estos no necesitan parámetros.
  • Hay varias otras operaciones, que se pueden encontrar en el manual. Pero, estos son los más utilizados por los usuarios interesados aptd. Hay opciones que se superponen con lo que apt-key, apt-cache, dpkghacer.

apt-geten sí mismo no es compatible con dichos métodos (para esperar otras instancias de apt), por lo que aptdcones la solución preferida para los administradores de paquetes de GUI: USC usa aptdcomo back-end, igual que Synaptic. Otra solución es packagekit, pero no es compatible con la función que está buscando (todavía).

Braiam
fuente
1
aptdcon --install /path/to/pgk.debFunciona como dpkg -i, aunque no pude encontrar esto explícitamente mencionado en el manual.
whitehat101
¿Puedo usar esto en el script posterior a la instalación en un paquete?
Nelson Teixeira
@NelsonTeixeira ¿por qué usarías esto en el script ppst-install? Si se está ejecutando la instalación posterior, obviamente, apt se está ejecutando.
Braiam el
Quiero hacer que postinstall instale algunos paquetes especiales que no están en el repositorio. Es posible ? Los incluiría en el paquete y luego el script los instalaría después de que finalice la instalación.
Nelson Teixeira
@NelsonTeixeira nuevamente, ¿por qué sería necesario? Los scripts posteriores a la instalación solo se ejecutan cuando hay una instalación de paquete. Le sugiero que haga una pregunta y explique su caso con más detalle.
Braiam el
18

Un enfoque muy simple sería un script que esperara a que el bloqueo no se abra. Vamos a llamarlo waitforapty pegarlo /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

Entonces solo corre sudo waitforapt && sudo apt-get install whatever. Puede agregar excepciones sudoerspara permitirle ejecutarlo sin necesidad de una contraseña (la necesitará para apt-getque no sea una gran ganancia).

Lamentablemente, esto no pone en cola las cosas. Dado que algunas de las operaciones de apt son interactivas ("¡¿Estás seguro de que quieres eliminar todos esos paquetes ?!"), no puedo ver una buena forma de evitar esto ...

Oli
fuente
¿Quizás -yasumir que sí para todas las operaciones?
Braiam
Gracias. Creo que puedo usarlo mejor si uso alias help.
rɑːdʒɑ
3
Sin -yembargo, no estoy seguro es deseable.
Oli
1
No creo que desee para envolver sudo fuseren [[ $(...) ]]. Devuelve un código de salida cero cuando se accede al archivo, por lo que debería ser suficiente.
kiri
44
Encontré que la siguiente solución es más completa, ya que hay varios bloqueos involucrados al trabajar con 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

Podría usar una técnica de sondeo:

$ time (while ps -opid= -C apt-get > /dev/null; do sleep 1; done); \
  apt-get -y install some-other-package
malta
fuente
mejor usoinotify
ctrl-alt-delor
3

Hice un script que hace esto:

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

Guarde lo anterior en /usr/local/sbin/apt-get. apt-getluego esperará si ya se está ejecutando otra instancia.

Alternativamente, guárdelo como /usr/local/sbin/apt-wait, ejemplo de uso:

apt-wait && aptitude

que se ejecutará aptitudedespués de que el proceso actual que mantiene el bloqueo haya salido

Ejemplo de ejecución:

  1. Primero, apt-getse ejecuta un comando, por ejemplo:

    $ sudo apt-get remove some_package
    
  2. Luego, en otra terminal, se ejecuta otro comando:

    $ sudo apt-get install some_other_package
    

    Esperará a que termine el primer comando y luego se ejecutará. Salida mientras espera:

    [/] Waiting for other package managers to finish...
          28223 : /usr/bin/apt-get remove some_package
    
kiri
fuente
1
mejor usoinotify
ctrl-alt-delor
3

Desafortunadamente, el fusor no hace mucho por usted cuando está ejecutando en diferentes contenedores de espacios de nombres sin privilegios como lxc.

Además, aptdcon no está instalado de manera predeterminada (al menos en 18.04) y pone en segundo plano su tarea en una cola para que pierda la serialización. Esto no es insuperable, pero significa que su automatización necesita tener alguna forma de evitar errores de flock en apt al instalar aptdcon, y necesitará tener algún tipo de bucles de espera para cualquier cosa que necesite serializar después de instalar paquetes a través de aptdcon a menos que ya haya algún tipo de bandera para eso.

Lo que funciona es rebaño. Esto también debería funcionar sobre NFS, etc., ya que utiliza el bloqueo del sistema de archivos de la misma manera que lo hace apt, solo con el parámetro -w segundos esperará en su bloqueo en lugar de arrojar un error.

Entonces, siguiendo el modelo de contenedor, agregue esto como apt-get in / usr / local / bin / y comparta.

Esto también tiene el beneficio de limitar IO al no permitir el paralelismo en apt para que pueda permitir que cron se active a medianoche en todas partes sin golpear el disco.

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

Una solicitud de función muy agradable y simple para apt-get sería una bandera -w para cambiar a un bloqueo / bloqueo de espera.

Raymond Ferguson
fuente
apt usa fcntl, no flock, por lo que esto no funcionará. askubuntu.com/questions/1077215/…
Andy
Esto funciona perfectamente y es una mejor opción que usar, fusercomo se muestra en muchas respuestas, ya fuserque todavía es propenso a las condiciones de carrera entre ver el bloqueo y el proceso de destino agarrar el bloqueo nuevamente. Con flockel bloqueo se adquiere y luego se pasa al proceso de destino, por lo que no deja tiempo para perder el bloqueo mientras tanto.
jrudolph
1

One-liner basado en la respuesta de Oli :

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