J'ai vu de nombreux logiciels tels que Update Manager et Synaptic Package Manager, ils attendent si un autre programme utilise le /var/lib/dpkg/lock
et est verrouillé. Comment pouvons-nous faire cela par le terminal? J'ai vu le manuel de apt-get
mais je n'ai rien trouvé d'utile.
Vous pouvez utiliser la commande aptdcon
mettre en file d'attente les tâches du gestionnaire de paquets en communiquant avec aptdaemon au lieu d'utiliser apt-get directement.
Donc, fondamentalement, vous pouvez simplement faire Sudo aptdcon --install chromium-browser
ou quoi que ce soit et tant que cette commande est exécutée, vous pouvez l'exécuter à nouveau, mais installer différents packages et apt-daemon les mettra en file d'attente au lieu de les supprimer.
Ceci est particulièrement utile si vous effectuez une mise à niveau longue ou quelque chose comme cela et que vous souhaitez continuer à installer des packages ou si vous écrivez quelque chose ensemble et que vous voulez vous assurer que l'installation sera plus fiable.
Vous pouvez créer apt-get
pour apprendre à attendre si un autre gestionnaire de logiciel est en cours d'exécution. Quelque chose de similaire avec le comportement de la prochaine distribution d'écran:
Je crée un nouveau script appelé apt-get
(wrapper for apt-get
) dans le répertoire /usr/local/sbin
avec le code bash suivant:
#!/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 "$@"
N'oubliez pas de le rendre exécutable:
Sudo chmod +x /usr/local/sbin/apt-get
Avant de tester, vérifiez si tout va bien. La sortie de la commande which apt-get
devrait maintenant être /usr/local/sbin/apt-get
. La raison est la suivante: par défaut, le répertoire /usr/local/sbin
est placé avant le répertoire /usr/bin
dans l'utilisateur ou la racine PATH
.
Outre l'évident &&
, vous pouvez rechercher aptdcon
name__. Cet outil est capable de détecter d'autres instances d'apt et d'attendre qu'elles se terminent:
Sudo aptdcon --safe-upgrade [/] 11% En attendant que d'autres gestionnaires de logiciels quittent le logiciel En attente d'aptitude
(Je cours d'aptitude ailleurs)
L'avantage de cet outil est que vous pouvez stocker plusieurs actions de manière consécutive sans vous inquiéter de ce que vous ferez ensuite. aptdcon
est idéal pour les scripts sans assistance et l’installation d’interface graphique, car vous pouvez autoriser l’exécution de l’outil en arrière-plan pour ne pas bloquer votre interface.
Les opérations supportées par aptdcon
sont les suivantes:
--refresh
, -c
: Ceci est l'équivalent de apt-get update
. Il met à jour votre liste de paquets.--install
, --remove
, --upgrade
, --purge
, --downgrade
. Chacun fait comme son nom l'indique. Le nom du ou des colis est obligatoire. -i
, -r
, -u
, -p
: ce sont les options abrégées pour toutes, sauf le déclassement, qui n'en ont pas.--safe-upgrade
, --full-upgrade
sont les homologues de apt-get
de upgrade
name __/dist-upgrade
et de aptitude
name__'s safe-upgrade
/full-upgrade
. Ceux-ci n'ont pas besoin de paramètres.aptd
name__. Certaines options se chevauchent avec ce que apt-key
, apt-cache
, dpkg
do.apt-get
lui-même ne supporte pas de telles méthodes (pour attendre d'autres instances d'apt), donc aptdcon
est la solution préférée des gestionnaires de paquets de l'interface graphique: USC utilise aptd
comme pour Back-end, comme pour Synaptic. Une autre solution est packagekit
name__, mais elle ne prend pas en charge la fonction que vous recherchez (pour le moment).
Une approche très simple serait un script qui attend que le verrou ne soit pas ouvert. Appelons-le waitforapt
et collez-le dans /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
Ensuite, lancez simplement Sudo waitforapt && Sudo apt-get install whatever
. Vous pouvez ajouter des exceptions dans sudoers
pour vous permettre de l'exécuter sans avoir besoin d'un mot de passe (vous en aurez besoin pour le apt-get
et vous ne gagnerez donc pas grand-chose).
Malheureusement, cela ne fait pas la queue. Étant donné que certaines opérations d'apt sont interactives ("Êtes-vous sûr de vouloir supprimer tous ces paquets?!"), Je ne vois pas comment contourner ce problème ...
J'ai fait un script qui fait ceci:
#!/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
Enregistrez ce qui précède dans /usr/local/sbin/apt-get
. apt-get
attendra ensuite si une autre instance est déjà en cours d'exécution.
Sinon, enregistrez-le sous /usr/local/sbin/apt-wait
, exemple d'utilisation:
apt-wait && aptitude
qui exécutera aptitude
après que le processus en cours contenant le verrou se soit terminé.
Exemple d'exécution:
Tout d'abord, une commande
apt-get
est exécutée, par exemple:$ Sudo apt-get remove some_package
Ensuite, dans un autre terminal, une autre commande est exécutée:
$ Sudo apt-get install some_other_package
Il attendra que la première commande se termine puis s’exécute. Sortie en attendant:
[/] Waiting for other package managers to finish... 28223 : /usr/bin/apt-get remove some_package
Vous pouvez utiliser une technique d'interrogation:
$ time (while ps -opid= -C apt-get > /dev/null; do sleep 1; done); \
apt-get -y install some-other-package
Malheureusement, fuser ne fait pas grand chose pour vous lorsque vous utilisez plusieurs conteneurs d’espace de noms non privilégiés comme lxc.
En outre, aptdcon n’est pas installé par défaut (au moins le 18.04) et met votre tâche en arrière-plan dans une file d’attente de sorte que vous perdiez la sérialisation. Ce n'est pas insurmontable, mais cela signifie que votre automatisation doit avoir un moyen d'éviter les erreurs de flock dans apt lors de l'installation d'aptdcon, et vous aurez besoin d'une sorte de boucle d'attente pour tout ce que vous devez sérialiser après avoir installé des paquets via aptdcon. sauf s'il existe déjà une sorte de drapeau pour cela.
Qu'est-ce que le travail est troupeau. Cela devrait également fonctionner sur NFS, etc., car il utilise le verrouillage de système de fichiers de la même façon qu'apt, mais avec le paramètre -w secondes, il attendra sur votre verrou au lieu de générer une erreur.
Donc, en suivant le modèle du wrapper, ajoutez ceci comme apt-get dans/usr/local/bin/et partagez-le.
Cela a également l'avantage de limiter IO en n'autorisant pas le parallélisme sur apt, vous pouvez donc laisser cron déclencher les mises à jour à minuit partout sans battre le disque.
#!/bin/bash
exec /usr/bin/flock -w 900 -F --verbose /var/cache/apt/archives/lock /usr/bin/apt-get $@
Une demande de fonctionnalité très simple et agréable pour apt-get serait un drapeau -w permettant de basculer vers un verrou bloquant/en attente.
One-Liner basé sur réponse d'Oli :
while Sudo fuser /var/{lib/{dpkg,apt/lists},cache/apt/archives}/lock >/dev/null 2>&1; do sleep 1; done