La shell di Linux e macOS spiegata da zero: comandi essenziali, text processing con grep/awk/sed, monitoraggio del sistema, networking, permessi e scripting completo con variabili, funzioni, cicli e cron. Con esempi pratici ed esercizi.
Introduzione a Bash
Bash (Bourne Again SHell) è l'interprete di comandi più diffuso nei sistemi Unix/Linux e macOS. Permette di eseguire comandi, automatizzare operazioni ripetitive e scrivere script potenti per la gestione del sistema.
Vantaggio
Descrizione
Universale
Presente su quasi tutti i sistemi Linux, macOS e WSL su Windows
Automazione
Automatizza task ripetitivi con script riutilizzabili
Potente
Combina piccoli comandi con le pipe per operazioni complesse
Leggero
Nessun ambiente da installare: è già nel terminale
In questo corso imparerai i comandi fondamentali, il text processing, il monitoraggio del sistema, il networking, la gestione dei file e la scrittura di script Bash completi.
Verifica la versione di Bash
bash --version
# GNU bash, version 5.1.16(1)-release (x86_64-pc-linux-gnu)
💡 Questo corso copre i fondamenti di Bash: la base indispensabile per usare Linux/macOS in modo efficiente e automatizzare il tuo lavoro.
Primi Passi con Bash
Il terminale è l'interfaccia dove digiti i comandi Bash. Su Linux puoi aprirlo con Ctrl+Alt+T; su macOS si trova in Applicazioni → Utility → Terminale.
Il prompt mostra informazioni utili prima del cursore: il simbolo $ indica un utente normale, mentre # indica il superutente (root).
Usa le frecce ↑↓ per scorrere i comandi precedenti, oppure history per l'elenco completo.
Cronologia e aiuto
history | tail -10 # ultimi 10 comandi usati
ls --help # aiuto rapido di un comando
man ls # manuale completo
Comando ls
ls elenca il contenuto di una directory. È uno dei comandi che userai più spesso.
Utilizzo base di ls
ls # directory corrente
ls /etc # directory specificata
ls -l # formato lungo (dettagliato)
ls -a # mostra file nascosti (iniziano con .)
ls -la # lungo + nascosti
ls -lh # dimensioni leggibili (KB, MB)
ls -lt # ordina per data di modifica
ls -lS # ordina per dimensione
Nel formato lungo, le colonne rappresentano: permessi, numero di link, proprietario, gruppo, dimensione, data e nome.
Output del formato lungo
-rw-r--r-- 1 user group 4096 Jun 12 10:00 file.txt
drwxr-xr-x 2 user group 4096 Jun 12 09:00 cartella/
Altre opzioni utili
ls -R # ricorsivo (include sottocartelle)
ls *.txt # solo i file .txt
ls -1 # un file per riga
Comando cd
cd (change directory) cambia la directory di lavoro corrente.
Navigare tra le directory
cd /etc # percorso assoluto
cd documenti # percorso relativo
cd .. # directory padre
cd ../.. # due livelli su
cd ~ # home dell'utente
cd - # directory precedente
Simbolo
Significato
~
home directory (/home/utente)
.
directory corrente
..
directory padre
/
radice del filesystem
💡 Premi Tab per completare automaticamente nomi di file e directory. Premilo due volte per vedere tutte le opzioni disponibili.
Comando pwd
pwd (print working directory) mostra il percorso assoluto della directory corrente.
echo -n "senza newline" # non va a capo
echo -e "riga1\nriga2" # \n = nuova riga
echo -e "tab\tspazio" # \t = tabulazione
Redirezione dell'output
echo "Contenuto" > file.txt # scrive (sovrascrive)
echo "Altro" >> file.txt # aggiunge in fondo
echo "Errore" >&2 # scrive su stderr
Comando cat
cat (concatenate) visualizza il contenuto di file, li concatena e può creare file semplici.
Visualizzare file
cat file.txt # mostra il contenuto
cat file1.txt file2.txt # mostra entrambi in sequenza
cat -n file.txt # con numeri di riga
cat -A file.txt # mostra caratteri non stampabili
Creare e concatenare file
# Creare un file (Ctrl+D per terminare)
cat > nuovo.txt
Scrivi qui il contenuto.
# Concatenare più file
cat parte1.txt parte2.txt > completo.txt
cat *.log > tutti_i_log.txt
Alternative per file lunghi
less file.txt # pagina per pagina (q per uscire)
more file.txt # simile a less
head -20 file.txt # prime 20 righe
tail -20 file.txt # ultime 20 righe
Comando cp
cp copia file e directory. Sintassi: cp [opzioni] sorgente destinazione.
Copiare file e directory
cp file.txt copia.txt # copia con nuovo nome
cp file.txt /tmp/ # copia in altra directory
cp file1.txt file2.txt /backup/ # copia più file
cp -r cartella/ backup/ # -r = ricorsivo (per le directory)
cp -r src/ /tmp/src_backup/
Opzioni utili
cp -i file.txt dest.txt # chiede conferma se dest esiste
cp -u file.txt dest.txt # copia solo se sorgente è più recente
cp -v file.txt dest.txt # verbose (mostra cosa fa)
cp -p file.txt dest.txt # preserva permessi e timestamp
cp -a cartella/ backup/ # archivio: -r + -p + symlink
Comando mv
mv sposta o rinomina file e directory. A differenza di cp, non serve -r per le directory.
Rinominare e spostare
# Rinominare
mv vecchio.txt nuovo.txt
mv vecchia_cartella/ nuova_cartella/
# Spostare
mv file.txt /tmp/ # sposta in /tmp
mv *.log /var/log/archivio/ # sposta tutti i .log
mv file1.txt file2.txt /dest/ # sposta più file
Opzioni e rinomina batch
mv -i src dest # chiede conferma prima di sovrascrivere
mv -n src dest # non sovrascrive mai (no-clobber)
mv -v src dest # verbose
# Rinomina tutti i .txt in .md con un ciclo
for f in *.txt; do
mv "$f" "${f%.txt}.md"
done
Comando rm
rm elimina file e directory.
⚠️ Attenzione: non esiste un cestino — l'eliminazione con rm è permanente. Non usare mai rm -rf / o rm -rf * senza la massima cautela.
Eliminare file e directory
rm file.txt
rm file1.txt file2.txt
rm *.tmp # elimina tutti i .tmp
rmdir cartella_vuota/ # solo se vuota
rm -r cartella/ # ricorsivo (anche con contenuto)
rm -rf cartella/ # forza senza conferme
Opzioni di sicurezza
rm -i file.txt # chiede conferma per ogni file
rm -I *.txt # chiede conferma una sola volta
rm -v file.txt # mostra cosa viene eliminato
# Alternativa sicura: cestino manuale
mkdir -p ~/cestino
mv file_da_eliminare.txt ~/cestino/
Comandi touch e mkdir
touch crea file vuoti o aggiorna il timestamp; mkdir crea directory.
Creare file e directory
# touch — file vuoti
touch file.txt # crea un file vuoto
touch file1.txt file2.txt # crea più file
# mkdir — directory
mkdir nuova_cartella
mkdir -p percorso/lungo/da/creare # crea tutti i livelli
mkdir -m 755 cartella # con permessi specifici
Struttura di un progetto
mkdir -p progetto/{src,tests,docs,assets}
touch progetto/README.md
touch progetto/src/main.sh
ls -R progetto/
💡 L'espansione con graffe è potentissima: mkdir -p backup/{2024,2025,2026}/{01..12} crea 36 directory anno/mese in una sola riga.
Comandi man e alias
man mostra il manuale di un comando; alias crea scorciatoie personalizzate.
Consultare il manuale
man ls # manuale di ls
man man # manuale di man stesso
man -k keyword # cerca per parola chiave
# Navigazione: Spazio=avanti, b=indietro, /parola=cerca, q=esci
Creare alias
alias ll='ls -lah'
alias la='ls -la'
alias ..='cd ..'
alias gs='git status'
alias aggiorna='sudo apt update && sudo apt upgrade'
alias # elenca gli alias attivi
unalias ll # rimuove un alias
Gli alias definiti nel terminale durano solo per la sessione corrente: aggiungili a ~/.bashrc per renderli permanenti.
Comando grep
grep cerca pattern (espressioni regolari) all'interno di file o input. È uno dei comandi più potenti di Bash.
Utilizzo base
grep "errore" log.txt # cerca "errore" in log.txt
grep "root" /etc/passwd # cerca l'utente root
grep "TODO" *.py # cerca in tutti i .py
Opzioni fondamentali
grep -i "errore" log.txt # case-insensitive
grep -r "TODO" ./src/ # ricorsivo nelle directory
grep -n "errore" log.txt # mostra il numero di riga
grep -c "errore" log.txt # conta le righe corrispondenti
grep -v "errore" log.txt # INVERSO: righe SENZA match
grep -l "TODO" *.py # solo i nomi dei file
grep -w "log" file.txt # solo parole intere
Espressioni regolari e pipe
grep "^#" script.sh # righe che iniziano con #
grep "\.py$" lista.txt # righe che finiscono con .py
grep -E "err(ore|or)" log.txt # pattern esteso
ps aux | grep python # processi Python
history | grep git # comandi git usati
Comando awk
awk è un linguaggio di elaborazione di testo orientato ai campi (colonne). Perfetto per file CSV, log e output di comandi.
Variabili chiave: $0 = riga intera, $1 = primo campo, NR = numero di riga, NF = numero di campi.
sed (stream editor) elabora e trasforma testo riga per riga. Ideale per sostituzioni in massa.
Sostituzione di testo
sed 's/vecchio/nuovo/' file.txt # prima occorrenza per riga
sed 's/vecchio/nuovo/g' file.txt # tutte le occorrenze
sed 's/vecchio/nuovo/gi' file.txt # case-insensitive
sed -i 's/vecchio/nuovo/g' file.txt # modifica il file
sed -i.bak 's/foo/bar/g' file.txt # salva backup .bak
Eliminare e stampare righe
sed '5d' file.txt # elimina la riga 5
sed '1,3d' file.txt # elimina le righe 1-3
sed '/^#/d' script.sh # elimina i commenti
sed '/^$/d' file.txt # elimina le righe vuote
sed -n '10,20p' file.txt # stampa solo le righe 10-20
sed -n '/errore/p' log.txt # stampa le righe con "errore"
Comandi cut, sort, head, tail
Questi comandi estraggono colonne, ordinano righe e mostrano porzioni di file. Combinati con le pipe diventano fortissimi.
cut e sort
# cut — estrae colonne
cut -d: -f1 /etc/passwd # primo campo separato da :
cut -d, -f2,4 dati.csv # colonne 2 e 4 da CSV
cut -c1-10 file.txt # caratteri 1-10
# sort — ordina righe
sort file.txt # ordine alfabetico
sort -n numeri.txt # ordine numerico
sort -r file.txt # ordine inverso
sort -k2 tabella.txt # ordina per seconda colonna
sort -u file.txt # rimuove i duplicati
head e tail
head file.txt # prime 10 righe (default)
head -n 20 file.txt # prime 20 righe
tail file.txt # ultime 10 righe
tail -n 20 file.txt # ultime 20 righe
tail -f /var/log/syslog # segue il file in tempo reale
Pipeline combinata
# Top 5 processi per uso CPU
ps aux | sort -k3 -rn | head -6 | awk '{print $1, $3"%", $11}'
Monitoraggio del Sistema
Questi comandi mostrano lo stato dei processi, della memoria e dei dischi.
Processi: ps e top
ps # processi del terminale corrente
ps aux # tutti i processi (a=tutti, u=utente, x=senza tty)
ps aux | grep nginx # cerca un processo specifico
top # monitor interattivo (q per uscire)
htop # versione migliorata (da installare)
# In top: M=ordina per memoria, P=CPU, k=termina, q=esci
Dischi e memoria: df, du, free
df -h # spazio disco leggibile (GB, MB)
df -h /home # solo /home
du -sh cartella/ # dimensione totale di una cartella
du -sh * | sort -h # ordina per dimensione
free -h # memoria RAM leggibile
free -h -s 2 # aggiorna ogni 2 secondi
Comandi kill e uptime
Ogni processo ha un PID (Process ID). kill invia segnali ai processi per terminarli.
Terminare processi
kill 1234 # SIGTERM (terminazione gentile)
kill -9 1234 # SIGKILL (forzata, immediata)
kill -l # elenco di tutti i segnali
# Trovare il PID
pidof nginx # PID di nginx
pgrep -u utente # PID dei processi dell'utente
# Terminare per nome
killall firefox # tutti i processi "firefox"
pkill -f "python app" # cerca nel comando completo
uptime — tempo di attività
uptime
# 10:30:15 up 5 days, 3:22, 2 users, load average: 0.15, 0.10, 0.09
w # chi è connesso + uptime
who # utenti connessi
last # cronologia degli accessi
Il load average mostra il carico medio negli ultimi 1, 5 e 15 minuti. Un valore minore o uguale al numero di CPU è considerato normale.
Comandi di Rete
Bash include strumenti per verificare la connettività, scaricare file e connettersi a server remoti.
ping, curl e wget
# ping — verifica connettività
ping -c 4 google.com # invia 4 pacchetti ICMP
# curl — trasferisce dati via URL
curl https://example.com # scarica una pagina
curl -o file.html https://example.com # salva in un file
curl -I https://example.com # solo header HTTP
curl -X POST -d "dati" https://api.example.com
# wget — scarica file
wget https://example.com/file.zip
wget -c https://example.com/grande.iso # riprende download
chown mario file.txt # cambia proprietario
chown mario:devs file.txt # proprietario e gruppo
chown -R mario:devs cartella/ # ricorsivo
chgrp devs file.txt # cambia solo il gruppo
Script Bash
Uno script Bash è un file di testo con comandi eseguiti in sequenza, perfetto per automatizzare operazioni ripetitive.
Struttura base di uno script
#!/bin/bash
# La prima riga (shebang) indica l'interprete
echo "Il mio primo script!"
date
whoami
FRUTTI=("mela" "banana" "ciliegia")
echo ${FRUTTI[0]} # mela
echo ${FRUTTI[@]} # tutti gli elementi
echo ${#FRUTTI[@]} # numero di elementi: 3
FRUTTI+=("pera") # aggiunge un elemento
# Array associativo (dizionario)
declare -A CAPITALI
CAPITALI["italia"]="Roma"
echo ${CAPITALI["italia"]} # Roma
Operatori
Bash usa operatori diversi per i confronti numerici (-eq, -lt...) e quelli sulle stringhe (=, !=).
Numerico
Significato
Stringhe
Significato
-eq
uguale
=
uguale
-ne
diverso
!=
diverso
-lt
minore
-z
stringa vuota
-gt
maggiore
-n
stringa non vuota
Operatori su file
[ -e percorso ] # esiste
[ -f percorso ] # è un file regolare
[ -d percorso ] # è una directory
[ -r percorso ] # è leggibile
[ -w percorso ] # è scrivibile
[ -x percorso ] # è eseguibile
[ -s percorso ] # esiste e non è vuoto
If / Else
I costrutti condizionali eseguono comandi diversi a seconda che una condizione sia vera o falsa.
Struttura if / elif / else
#!/bin/bash
ETA=$1
if [ -z "$ETA" ]; then
echo "Uso: $0 <eta>"
exit 1
fi
if [ "$ETA" -ge 18 ]; then
echo "Sei maggiorenne"
elif [ "$ETA" -ge 13 ]; then
echo "Sei un adolescente"
else
echo "Sei un bambino"
fi
Operatori logici
# AND: entrambe le condizioni vere
if [ "$ETA" -ge 18 ] && [ "$ETA" -lt 65 ]; then
echo "Eta lavorativa"
fi
# OR: almeno una vera
if [ "$GIORNO" = "sabato" ] || [ "$GIORNO" = "domenica" ]; then
echo "E weekend"
fi
Case statement
case "$FRUTTO" in
"mela"|"pera")
echo "Frutto di stagione"
;;
"banana")
echo "Frutto esotico"
;;
*)
echo "Frutto sconosciuto"
;;
esac
Loop
I cicli ripetono blocchi di comandi. Bash offre for, while e until.
Ciclo for
# Lista esplicita
for FRUTTO in mela banana ciliegia; do
echo "Frutto: $FRUTTO"
done
# Range numerico
for i in {1..10}; do
echo "Numero: $i"
done
# C-style
for ((i=0; i<5; i++)); do
echo "i=$i"
done
# File in una directory
for file in *.txt; do
echo "Elaboro: $file"
done
Cicli while e until
CONTATORE=0
while [ $CONTATORE -lt 5 ]; do
echo "Contatore: $CONTATORE"
((CONTATORE++))
done
# Leggere un file riga per riga
while IFS= read -r riga; do
echo "Riga: $riga"
done < file.txt
break e continue
for i in {1..10}; do
[ $i -eq 5 ] && continue # salta il 5
[ $i -eq 8 ] && break # esce all'8
echo $i
done
Funzioni
Le funzioni raggruppano comandi riutilizzabili. Restituiscono codici di uscita (0-255); per i dati si usa echo e la sostituzione di comando.
#!/bin/bash
log() {
local livello=$1
local messaggio=$2
echo "[$(date '+%H:%M:%S')] [$livello] $messaggio"
}
verifica_file() {
local percorso=$1
if [ ! -f "$percorso" ]; then
log "ERRORE" "File non trovato: $percorso"
return 1
fi
log "INFO" "File trovato: $percorso"
return 0
}
verifica_file "/etc/passwd" && log "OK" "Tutto bene"
Cron — Pianificazione
cron esegue comandi automaticamente a intervalli pianificati, configurati tramite il crontab.
Gestire il crontab
crontab -e # apre l'editor del crontab
crontab -l # elenca i job configurati
crontab -r # rimuove tutti i job
Formato del crontab
# minuto ora giorno mese giorno_settimana comando
# (0-59) (0-23) (1-31) (1-12) (0-7, 0=dom)
0 9 * * 1-5 /home/user/backup.sh # Lun-Ven alle 09:00
30 2 * * * /usr/bin/backup # ogni giorno alle 02:30
*/15 * * * * /scripts/check.sh # ogni 15 minuti
0 0 1 * * /scripts/monthly.sh # primo del mese a mezzanotte
@reboot /scripts/startup.sh # all'avvio del sistema
Scorciatoie speciali
@hourly # ogni ora @daily # ogni giorno
@weekly # ogni settimana @monthly # ogni mese
@yearly # ogni anno @reboot # all'avvio
Esercizi Bash
Metti alla prova le tue conoscenze con questi esercizi pratici. Prova a risolverli prima di guardare la soluzione.
🎯 Esercizio 1 — Backup automatico
Scrivi uno script che faccia il backup di una directory, nomini l'archivio con la data e mantenga solo gli ultimi 7 backup.
Soluzione 1
#!/bin/bash
SORGENTE="$1"
DEST_DIR="$HOME/backup"
DATA=$(date +%Y%m%d_%H%M%S)
mkdir -p "$DEST_DIR"
tar -czvf "$DEST_DIR/backup_$DATA.tar.gz" "$SORGENTE"
# Mantieni solo gli ultimi 7
ls -t "$DEST_DIR"/backup_*.tar.gz | tail -n +8 | xargs rm -f
echo "Backup completato."
🎯 Esercizio 2 — Monitor disco
Scrivi uno script che avverta se un filesystem supera l'80% di utilizzo.
Soluzione 2
#!/bin/bash
SOGLIA=80
df -h | awk -v s=$SOGLIA 'NR>1 {
gsub(/%/, "", $5)
if ($5+0 > s) {
print "AVVISO: " $6 " e al " $5 "%"
}
}'
🎯 Esercizio 3 — Rinomina batch
Rinomina tutti i file .jpeg in .jpg in una directory.
Soluzione 3
#!/bin/bash
DIR="${1:-.}"
CONTATORE=0
for file in "$DIR"/*.jpeg; do
[ -f "$file" ] || continue
mv "$file" "${file%.jpeg}.jpg"
((CONTATORE++))
done
echo "Totale rinominati: $CONTATORE"
Conclusione
Hai completato il corso di Bash! Hai imparato a navigare il filesystem, elaborare testo con grep/awk/sed, monitorare il sistema, gestire la rete, comprimere file, impostare i permessi e scrivere script completi con variabili, funzioni, cicli e pianificazione automatica con cron.
Bash è uno strumento che cresce con l'esperienza: più script scrivi, più diventa naturale. Continua ad esplorare i man page e non smettere di automatizzare il tuo lavoro!
🎓 Prossimo passo consigliato: ora che padroneggi la shell, approfondisci la programmazione con il corso Python per automazioni ancora più potenti.