Prima di leggere: quattro domande alternate
Nella lezione precedente hai imparato la famiglia Debian. Qui impari l'altra, e non le imparerai una dopo l'altra: le imparerai alternate, perché è l'unico modo di non confonderle. Queste quattro domande non sono un ripasso, sono il modo in cui la lezione è costruita. Rispondi prima di proseguire.
- Quale comando ti dice a quale pacchetto appartiene un file, su Debian?
- Quale programma scarica e risolve le dipendenze, su Debian?
- Quale comando ti dice se un pacchetto è installato, su Debian?
- Che cosa fa
apt removee che cosa lascia?
Tieni queste quattro risposte sotto gli occhi. Per ciascuna, nel corso della lezione, troverai la corrispondente dell'altra famiglia, e la domanda che ti farò ogni volta è la stessa: è lo stesso concetto con un nome diverso, oppure è un concetto diverso?
Il problema: due famiglie, e un giorno su una macchina dell'altra
Se hai imparato su Ubuntu, prima o poi finisci su una macchina Red Hat, CentOS, Rocky, Fedora o Amazon Linux, e succede nel momento sbagliato: un incidente, un contenitore di qualcun altro, una pipeline che gira su un'immagine che non hai scelto tu. I concetti sono gli stessi e i comandi sono tutti diversi, e la tentazione è imparare a memoria una tabella di traduzione.
La tabella di traduzione funziona male per un motivo preciso: due coppie di comandi che la tabella presenta come equivalenti non lo sono, e sono proprio quelle su cui si fa danno. Alternare le due famiglie invece di studiarle in blocco serve a questo: a notare dove la corrispondenza regge e dove si rompe.
Tutti gli output di questa lezione vengono da un contenitore Fedora 43 che ho eseguito il
2026-10-30. Il motivo per cui te lo dico è che la mia macchina è Ubuntu, quindi non posso provare
dnf su di essa, e un contenitore è il modo onesto di avere output veri invece di output
ricordati. È anche il modo con cui puoi rifarli tu.
I due livelli, di nuovo, con altri nomi
La struttura è la stessa della famiglia Debian: uno strumento di basso livello che tratta i pacchetti
che hai in mano, e uno di alto livello che conosce i repository e risolve le dipendenze. Qui si
chiamano rpm e dnf.
$ grep -E '^(NAME|VERSION_ID)=' /etc/os-release
NAME="Fedora Linux"
VERSION_ID=43
$ dnf --version
dnf5 version 5.2.18.0
$ rpm --version
RPM version 6.0.2
Prima risposta alla prima domanda d'apertura. Su Debian il comando è dpkg -S percorso;
qui è rpm -qf percorso, dove -q significa interroga e -f
significa «per questo file».
$ rpm -qf /usr/bin/ls
coreutils-9.7-10.fc43.x86_64
Nota la forma del nome: nome-versione-release.architettura, tutto in una stringa. È una
differenza di presentazione che diventa sostanziale quando scrivi uno script, perché su Debian nome e
versione sono campi separati e qui vanno estratti da una stringa, oppure chiesti con un formato
dichiarato.
E nota il contenuto, che risponde a una domanda di una lezione precedente. Qui ls
appartiene a coreutils versione 9.7, e
ls --version risponde ls (GNU coreutils) 9.7: la riscrittura in Rust che su
Ubuntu 26.04 aveva sostituito centootto comandi, su Fedora 43 non c'è. La domanda «quale programma
sto eseguendo» ha una risposta diversa su ogni famiglia, e questo è il motivo per cui va fatta.
Seconda e terza domanda. Per sapere se un pacchetto è installato, su Debian usavi
dpkg-query; qui è rpm -q. Per i dettagli e per l'elenco dei file, le due
opzioni sono -qi e -ql.
$ rpm -qa | wc -l
142
$ rpm -qi coreutils
Name : coreutils
Version : 9.7
Release : 10.fc43
Architecture: x86_64
Install Date: Tue Aug 25 05:47:41 2026
Size : 5648233
License : GPL-3.0-or-later AND GFDL-1.3-no-invariants-or-later AND LGPL-2.1-or-later AND LGPL-3.0-or-later
$ rpm -ql coreutils | grep "^/usr/bin/" | head -6
/usr/bin/[
/usr/bin/arch
/usr/bin/b2sum
/usr/bin/base32
/usr/bin/base64
/usr/bin/basename
Centoquarantadue pacchetti in questo contenitore, contro i duemilaottocentosedici della mia macchina completa: il confronto dice qualcosa sul contenitore, non sulla distribuzione, ed è utile averlo in mente quando diagnostichi un'immagine minimale in cui metà degli strumenti non c'è.
Dove la traduzione si rompe, prima volta
Quarta domanda d'apertura: che cosa lascia apt remove. La risposta era «i file di
configurazione», in stato rc, e per toglierli serviva purge. Qui la
corrispondenza non regge, e la differenza è strutturale.
Il formato RPM non ha il concetto di «pacchetto rimosso con configurazione residua»: un pacchetto è
installato oppure non c'è, e rpm -qa non elenca stati intermedi. I file di
configurazione vengono trattati in modo diverso: quando un pacchetto viene rimosso, un file di
configurazione che hai modificato viene rinominato con un suffisso e lasciato, invece di restare
registrato come residuo del pacchetto. Quindi la domanda «quali pacchetti hanno lasciato
configurazione» che su Debian ha una risposta esatta, qui non ha un comando: si cercano i file con
quel suffisso.
L'errore di classificazione plausibile, e vale la pena nominarlo perché l'ho visto in una tabella di
traduzione pubblicata, è scrivere che dnf remove corrisponde ad apt purge.
Non corrisponde a nessuno dei due in modo esatto: il meccanismo dei residui è diverso, quindi la
domanda da farsi su una macchina RPM non è «ho fatto purge» ma «ci sono file con il suffisso dei
file di configurazione salvati».
La seconda coppia che non si traduce riguarda i repository. Su Debian le fonti stanno in file di
elenco e le priorità si leggono con apt-cache policy; qui le fonti stanno in file sotto
/etc/yum.repos.d/, ciascuno con un proprio identificativo, e il meccanismo di priorità
di base non esiste nella stessa forma: i conflitti si risolvono per versione, e la precedenza fra
repository richiede un modulo aggiuntivo. Concludere che «la policy di apt corrisponde a qualcosa in
dnf» porta a cercare un comando che non c'è.
Esempio svolto: la differenza fra i due livelli, provata
Il problema: hai un file di pacchetto scaricato e lo devi installare. Esistono due comandi che lo fanno, e vuoi sapere perché ne esistono due.
L'informazione disponibile: rpm non conosce i repository e dnf sì. Il
ragionamento: se un pacchetto ha dipendenze non soddisfatte, lo strumento di basso livello non può
procurarsele, quindi deve rifiutare; quello di alto livello può. La prova si fa su un pacchetto con
dipendenze vere, e httpd ne ha.
$ dnf download httpd
httpd-0:2.4.69-1.fc43.x86_64 100% | 235.2 KiB/s | 46.3 KiB | 00m00s
$ rpm -i ./httpd-2.4.69-1.fc43.x86_64.rpm
error: Failed dependencies:
httpd-core = 0:2.4.69-1.fc43 is needed by httpd-2.4.69-1.fc43.x86_64
system-logos(httpd-logo-ng) is needed by httpd-2.4.69-1.fc43.x86_64
systemd is needed by httpd-2.4.69-1.fc43.x86_64
$ echo $?
1
$ dnf -y install ./httpd-2.4.69-1.fc43.x86_64.rpm
httpd x86_64 2.4.69-1.fc43 @commandline 56.6 KiB
apr x86_64 1.7.6-3.fc43 fedora 299.6 KiB
apr-util x86_64 1.6.5-1.fc43 updates 219.7 KiB
httpd-core x86_64 2.4.69-1.fc43 updates 4.5 MiB
httpd-tools x86_64 2.4.69-1.fc43 updates 198.1 KiB
mod_http2 x86_64 2.0.39-1.fc43 updates 431.5 KiB
Installing: 45 packages
Lo stesso file, due esiti. rpm -i elenca le tre dipendenze che gli mancano e si ferma
con codice uno. dnf install sullo stesso file risolve e installa
quarantacinque pacchetti: uno è quello che gli ho dato, marcato
@commandline perché viene dalla riga di comando e non da un repository, e
quarantaquattro li ha trovati lui.
La decisione che prendo: rpm -i non lo uso quasi mai, e quando lo uso è perché voglio
esattamente quel comportamento, cioè il rifiuto in assenza di dipendenze. L'alternativa che ho visto
praticare e che va evitata è aggiungere l'opzione che salta il controllo delle dipendenze: il
pacchetto si installa, il programma non parte, e il sistema resta in uno stato che il gestore
considera coerente mentre non lo è. È il modo più rapido di rendere una macchina difficile da
riparare.
La verifica, e qui c'è un richiamo a una lezione precedente che vale la pena fare. La prima volta che
ho eseguito quel comando avevo scritto rpm -i *.rpm | head -12 per abbreviare l'output,
e il codice di uscita stampato era zero. Rieseguito senza la barra verticale,
rpm lascia uno:
$ rpm -i ./httpd-*.rpm > /tmp/out.txt 2>&1; echo "rpm exit=$?"
rpm exit=1
$ rpm -i ./httpd-*.rpm 2>&1 | head -1 > /dev/null; echo "PIPESTATUS=${PIPESTATUS[*]}"
PIPESTATUS=1 0
È esattamente il difetto della lezione sui comandi fondamentali: in una catena il codice che resta è
quello dell'ultimo comando. L'errore che avrei potuto commettere, e che per un momento ho commesso,
è concludere che rpm fallisce silenziosamente con codice zero. Falliva con uno; era
head a riuscire.
Esercizio 1, intercalato: completa la tabella in entrambe le direzioni
Per ciascuna delle righe seguenti, scrivi il comando mancante e dichiara se la corrispondenza è esatta oppure approssimata. Per le approssimate, scrivi in che cosa differiscono. Due righe sono già fatte come modello, e nota che nelle prime due il senso della traduzione è invertito di proposito.
- Debian
dpkg -S percorso→ RPMrpm -qf percorso. Esatta. - RPM
rpm -ql pacchetto→ Debiandpkg -L pacchetto. Esatta. - Debian
apt-cache policy pacchetto→ RPM ? - RPM
dnf remove pacchetto→ Debian ? - Debian
apt-mark showmanual→ RPM ? - RPM
rpm -V pacchetto→ Debian ?
Esercizio 2, autonomo: la stessa domanda su due macchine
Avvia un contenitore di una distribuzione della famiglia RPM e rispondi, su quella macchina, alle tre domande quantitative della lezione precedente: quanti pacchetti installati, quanti richiesti esplicitamente, quanti con residui di configurazione. Poi confronta con i numeri della tua macchina. Criterio di successo: per ciascuna delle tre domande hai il comando della famiglia RPM, e per almeno una sai dire che la domanda non ha un equivalente diretto e perché.
Soluzioni commentate
Riga 3. La risposta più vicina è dnf repoquery --info pacchetto, e la
corrispondenza è approssimata. Il comando dice la versione disponibile e il
repository di provenienza, che è gran parte di quello che dava apt-cache policy, e non
dice le priorità, perché come hai letto sopra quel meccanismo di base non c'è. Chi cerca la colonna
dei numeri di priorità in questa famiglia la cerca a lungo.
Riga 4. La risposta è che corrisponde a nessuno dei due, ed è la
riga che l'esercizio esiste per fare sbagliare. dnf remove non è apt remove
perché non lascia un pacchetto in stato residuo, e non è apt purge perché i file di
configurazione modificati vengono comunque conservati, con un altro nome. Chi scrive «equivale a
purge» produce una tabella che fa prendere decisioni sbagliate su una macchina di produzione.
Riga 5. La risposta è dnf repoquery --userinstalled, e la
corrispondenza è approssimata per un motivo che vale la pena capire: le due famiglie registrano
questa informazione in momenti diversi della storia della macchina. Un pacchetto installato prima che
quel registro esistesse, o installato con lo strumento di basso livello, non compare. Quindi il
numero che ottieni è una risposta utile e non è un inventario completo, e questo vale anche per
apt-mark showmanual.
Riga 6. La risposta è dpkg --verify, cioè lo strumento dell'esercizio
autonomo della lezione precedente, e qui la corrispondenza è esatta nel concetto: entrambi
confrontano i file installati con le somme di controllo registrate. Vale però la stessa avvertenza:
un file di configurazione modificato da te compare come differente, e «differente» non significa
«compromesso».
Esercizio 2. La terza domanda è quella che non ha equivalente, ed è il punto. Le
prime due si rispondono con rpm -qa | wc -l e
dnf repoquery --userinstalled | wc -l. Per la terza non esiste un comando che elenchi i
pacchetti con residui di configurazione, perché in questa famiglia quello stato non esiste: la
domanda equivalente è «esistono file di configurazione salvati da una rimozione», e si risponde
cercando i file con il suffisso corrispondente sotto /etc.
Perché sui numeri non vale la pena confrontare i miei con i tuoi. In un contenitore Fedora 43 ho contato centoquarantadue pacchetti, contro i duemilaottocentosedici della mia installazione completa di Ubuntu: la differenza misura la differenza fra un contenitore e un sistema desktop, non fra due distribuzioni. Un confronto onesto fra le due famiglie richiederebbe due installazioni comparabili, e non ce l'ho: quindi il numero resta un dato sul mio contenitore e non diventa un'affermazione sulle distribuzioni.
Che cosa adesso sai fare
Sai operare sulla famiglia RPM conoscendo la struttura a due livelli invece di una tabella di
comandi: sai che rpm interroga e tratta i file che hai, e che dnf conosce
i repository e risolve. Lo hai provato sullo stesso file di pacchetto, ottenendo tre dipendenze
mancanti dal primo e quarantacinque pacchetti installati dal secondo.
Sai anche dove la traduzione fra le due famiglie si rompe, e sono due punti precisi: i residui di
configurazione dopo una rimozione, e le priorità fra repository. Sapere dove una corrispondenza non
regge vale più che ricordarne dieci che reggono. La verifica concreta: avvia un contenitore di una
distribuzione RPM e risali al pacchetto che possiede /usr/bin/ls, poi confronta la sua
versione con quella della tua macchina.