#!/bin/bash # Nom : ahr Apt History Research # # Par : Tawal # # Nécessite : gawk (apt install gawk) # version=2023-06-08-22:05 ### Répertoire des logs d'apt (personnalisable) apt_folder="/var/log/apt" ### Formats Textes Surb='\e[1m' # Surbrillance Ital='\e[3m' # Italique Rst='\e[m' # Reset ### Expressions régulières # Entier (option -z) rgx_int="^[[:digit:]]+$" # Format de DATE (option -d.) rgx_date="^[[:digit:]]{4}($|-(0[1-9]|1[0-2])($|-(0[1-9]|[1-2][0-9]|3[0-1])($| ([0-1][0-9]|2[0-3])($|:[0-5][0-9]))))$" ### Fonctions usage_quit() { echo -e "Apt History Research - ahr - $version Usage : ${Surb}${0##*/} [-a | -z N] [--apt [-0]] [-c COMMAND] [-d DATE] [-t TYPE] MOTIF${Rst} ${Surb}${0##*/} -c COMMAND [-a | -z N] [--apt [-0]] [-d DATE] [-t TYPE] [MOTIF]${Rst} ${Surb}${0##*/} -d DATE [-a | -z N] [--apt [-0]] [-c COMMAND] [-t TYPE] [MOTIF]${Rst} ${Surb}${0##*/} -t TYPE [-a | -z N] [--apt [-0]] [-c COMMAND] [-d DATE] [MOTIF]${Rst} Outil de recherche dans l'historique d'apt. Recheche sur ${Surb}MOTIF${Rst} ou ${Surb}COMMAND${Rst} ou ${Surb}DATE${Rst} ou ${Surb}TYPE${Rst}. Si plusieurs champs de recherche sont indiqués, alors applique un ET. Options : -a, --all Rechercher dans tout l'historique, même archivé. Imcompatible avec '${Ital}-z${Rst}'. -c, --command ${Surb}COMMAND${Rst} Rechercher sur la commande ${Surb}COMMAND${Rst}. -d, --date ${Surb}DATE${Rst} Rechercher sur la date ${Surb}DATE${Rst} affinée avec l'heure. Format : ${Surb}AAAA[-MM[-JJ[ HH[:MM[:SS]]]]]${Rst} -h, --help Afficher cette aide et quitter. -t, --type ${Surb}TYPE${Rst} Rechercher selon le ${Surb}TYPE${Rst}, ${Surb}TYPE${Rst} prend les valeurs : ${Surb}Install${Rst}, ${Surb}Reinstall${Rst}, ${Surb}Upgrade${Rst}, ${Surb}Remove${Rst} et ${Surb}Purge${Rst} -z, --dezip ${Surb}N${Rst} Rechercher dans le fichier archive ${Surb}N${Rst} : ${Ital}$apt_folder/history.log.${Surb}N${Rst}${Ital}.gz${Rst} Imcompatible avec '${Ital}-a${Rst}'. -v, --version Afficher la version et quitter. --apt N'afficher que la liste des noms des paquets. Le retour est utilisable par ${Ital}apt${Rst} ou ${Ital}dpkg${Rst}. Un nom de paquet par ligne. -0 Seulement avec '${Ital}--apt${Rst}'. Utiliser le caractère NULL pour séparateur de nom de paquet et pas le retour à la ligne. ${Surb}MOTIF${Rst} est une partie ou un nom exact de paquet. ${Surb}COMMAND${Rst} est une partie ou la commande appelant l'action d'apt. ${Surb}DATE${Rst} est une partie ou la date de début de l'action d'apt. ${Surb}TYPE${Rst} est le type d'action d'apt." printf "%80s\n" "Tawal®©" exit 0 } version_quit() { echo "$version" exit } erreur_quit() { echo -n "${0##*/} : " [ "$1" = "log" ] && echo -e "Le fichier '$apt_folder/history.log' n'existe pas." [ "$1" = "zip" ] && echo -e "Le fichier '$apt_folder/history.log.$2.gz' n'existe pas." [ "$1" = "opt" ] && echo -e "Option ${Surb}'$2'${Rst} non-reconnue." [ "$1" = "opt0" ] && echo -e "Option '${Surb}-0${Rst}' utilisée sans '${Surb}--apt${Rst}'." [ "$1" = "motif" ] && echo -e "Motif absent ou pas d'utilisation d'une des options '${Surb}-c${Rst}' ou '${Surb}-d${Rst}' ou '${Surb}-t${Rst}'." [ "$1" = "opt_az" ] && echo -e "Options '${Surb}-a${Rst}' et '${Surb}-z${Rst}' incompatibles." [ "$1" = "opt_z" ] && echo -e "L'argument de l'option ${Surb}'-z'${Rst} doit être un nombre." [ "$1" = "opt_t" ] && echo -e "L'option ${Surb}-t${Rst} ne prend que les mots ${Surb}Install${Rst}, ${Surb}Reinstall${Rst}, ${Surb}Upgrade${Rst}, ${Surb}Remove${Rst} et ${Surb}Purge${Rst}." [ "$1" = "opt_d" ] && echo -e "Date incorrecte : ${*:2}" [[ $1 =~ gawk|zcat ]] && echo -e "Nécessite ${Ital}${BASH_REMATCH[0]}${Rst} : apt install ${BASH_REMATCH[0]}" exit 1 } >&2 test_opt() { [ "$1" = "opt_t" ] && [ "$2" != "Install" ] && \ [ "$2" != "Remove" ] && [ "$2" != "Upgrade" ] && \ [ "$2" != "Reinstall" ] && [ "$2" != "Purge" ] && return 1 [ "$1" = "opt_d" ] && ! [[ "$2" =~ $rgx_date ]] && return 1 [ "$1" = "opt_z" ] && ! [[ "$2" =~ $rgx_int ]] && return 1 return 0 } input2treat() { local i f n zap="$1" declare -a LogFich idx shift if [ "$1" = "all" ] then for f in "$apt_folder"/hist*gz do n="${f%.*}"; n="${n##*.}" LogFich[n]="$f" done # shellcheck disable=SC2206 idx=( ${!LogFich[@]} ) for ((i=${#idx[@]}-1; i>=0; i--)) do zcat "${LogFich[${idx[i]}]}" done [ ! "$zap" ] && cat "$apt_folder"/history.log elif [ "$1" = "one" ] then zcat "$apt_folder"/history.log."$2".gz else cat "$apt_folder"/history.log fi } ### Gestion des Options. shopt -s extglob nullglob while getopts :ac:d:ht:vz:-:0 option do case $option in a) opt_a="on" [ "$opt_z" ] && erreur_quit opt_az dezip_type="all" ;; c) opt_c="$OPTARG" ;; d) opt_d="$OPTARG" test_opt opt_d "$opt_d" || erreur_quit opt_d "$opt_d" ;; z) opt_z="on" [ "$opt_a" ] && erreur opt_az test_opt opt_z "$OPTARG" || erreur_quit opt_z dezip_type="one" dezip_nb="$OPTARG" ;; h) usage_quit ;; t) opt_t="$OPTARG" test_opt opt_t "$opt_t" || erreur_quit opt_t ;; v) version_quit ;; 0) opt_null="on" ;; -) case $OPTARG in all) opt_a="on" [ "$opt_z" ] && erreur_quit opt_az dezip_type="all" ;; apt) opt_apt="on" ;; command) opt_c="${!OPTIND}" OPTIND=$((OPTIND+1)) ;; date) opt_d="${!OPTIND}" test_opt opt_d "$opt_d" || erreur_quit opt_d OPTIND=$((OPTIND+1)) ;; dezip) opt_z="on" [ "$opt_a" ] && erreur opt_az test_opt opt_z ${!OPTIND} || erreur_quit opt_z dezip_type="one" dezip_nb=${!OPTIND} OPTIND=$((OPTIND+1)) ;; help) usage_quit ;; type) opt_t=${!OPTIND} test_opt opt_t "$opt_t" || erreur_quit opt_t OPTIND=$((OPTIND+1)) ;; version) version_quit ;; *) erreur_quit opt --"$OPTARG" ;; esac ;; *) erreur_quit opt -"$OPTARG" ;; esac done shift $((OPTIND-1)) if ! hash gawk 2>/dev/null then erreur_quit gawk fi if ! hash zcat 2>dev/null then erreur_quit zcat fi if [ "$1" ] then rech="$1" elif [ ! "$opt_c" ] && [ ! "$opt_d" ] && [ ! "$opt_t" ] then erreur_quit motif fi if [ "$opt_null" ] && [ ! "$opt_apt" ] then erreur_quit opt0 fi if [ "$opt_z" ] then [ -e "$apt_folder"/history.log."$dezip_nb".gz ] || erreur zip "$dezip_nb" else if ! [ -e "$apt_folder"/history.log ] then if [ "$opt_a" ] then zap="on" else erreur_quit log fi fi fi ### Corps du programme # shellcheck disable=SC1004 gawk -vrech="$rech" -vopt_c="$opt_c" -vopt_d="$opt_d" -vopt_t="$opt_t" -vapt="$opt_apt" -vnull="$opt_null" ' function afficher(verb, zero, mess, Array, ArrayTmp, tmp, k,n) { if (0 in Array) { if (!verb && mess) {print mess} for (n in Array) { if (tmp && Array[n] ~ /,/) { ArrayTmp[k++]=Array[n] continue } if (!verb) {printf("\t")} printf(Array[n]) if (zero) {printf("\0")}else{printf("\n")} } } } BEGIN { PROCINFO["sorted_in"]="@val_str_asc" } { if ($1 ~/Start/) { start="Date Début : "$2" "$3 date=$2" "$3 ok=0 next } if ($1 ~ /Commandline/) { command=gensub($1" ", "", 1) next } if ($1 ~ /Requested-By/) { demand=gensub($1" ", "", 1) next } if ($1~ /End/) { end="Date Fin : "$2" "$3 ok=1 } if (opt_c && command ~ opt_c) {opt_c_ok=1} if (opt_d && date ~ opt_d) {opt_d_ok=1} if (opt_t && $1 ~ opt_t) {opt_t_ok=1} if (rech && $0 ~ rech) {rech_ok=1} if ((opt_c_ok && opt_d_ok && rech_ok && opt_t_ok) || \ (!opt_c && opt_d_ok && rech_ok && opt_t_ok) || \ (!opt_c && !opt_d && rech_ok && opt_t_ok) || \ (opt_c_ok && !opt_d && rech_ok && opt_t_ok) || \ (opt_c_ok&& opt_d_ok && !rech && opt_t_ok) || \ (!opt_c && opt_d_ok && !rech && opt_t_ok) || \ (opt_c_ok && !opt_d && !rech && opt_t_ok) || \ (opt_c_ok && opt_d_ok && rech_ok && !opt_t) || \ (!opt_c && opt_d_ok && rech_ok && !opt_t) || \ (!opt_c && !opt_d && rech_ok && !opt_t) || \ (opt_c_ok && !opt_d && rech_ok && !opt_t) || \ (opt_c_ok && opt_d_ok && !rech && !opt_t) || \ (!opt_c && opt_d_ok && !rech && !opt_t) || \ (opt_c_ok && !opt_d && !rech && !opt_t) || \ (!opt_c && !opt_d && !rech && opt_t_ok)) { ok1=1 } opt_c_ok=0; opt_d_ok=0; opt_t_ok=0; rech_ok=0 if (ok1) { for (v=2; v<=NF-1; v++) { if ($v !~ /,/) { if (apt) { paq=$v }else{ if ($(v+2) ~ /)/) { der=gensub(",", "", 1, $(v+2)) paq=$v" "$(v+1)" "der }else{ pre=gensub(",", "", 1, $(v+1)) paq=$v" "pre } } if ($1 ~ /Install:/) { I[a++]=paq }else if ($1 ~ /Upgrade:/) { U[b++]=paq }else if ($1 ~ /Remove:/) { R[c++]=paq }else if ($1 ~ /Purge:/) { P[d++]=paq }else if ($1 ~ /Reinstall:/) { Re[e++]=paq } } } } if (ok && ok1) { if (!apt) { printf("\n") print start print end if (command) {print "Commande : "command} if (demand) {print "Demandeur : "demand} } afficher(apt, null, "Installés :", I, Itmp, "on") afficher(apt, null, "", Itmp) afficher(apt, null, "Upgradés :", U) afficher(apt, null, "Désinstallés :", R) afficher(apt, null, "Purgés :", P) afficher(apt, null, "Réinstallés :", Re) if (!apt) { if (a>1) {s1="s"}else{s1=""} if (b>1) {s2="s"}else{s2=""} if (c>1) {s3="s"}else{s3=""} if (d>1) {s4="s"}else{s4=""} if (e>1) {s5="s"}else{s5=""} if (a>0) {print a,"paquet"s1" installé"s1} if (b>0) {print b,"paquet"s2" upgradé"s2} if (c>0) {print c,"paquet"s3" désinstallé"s3} if (d>0) {print d,"paquet"s4" purgé"s4} if (e>0) {print e,"paquet"s5" réinstallé"s5} printf("\n") } delete I; delete U; delete R; delete P; delete Re; delete Itmp command="" date="" demand="" a=0; b=0; c=0; d=0; e=0; ok=0; ok1=0 } } ' < <(input2treat "$zap" "$dezip_type" "$dezip_nb")