Fondamenti & Esecuzione dei File
Uno script Bash non è altro che un file di testo contenente una sequenza di comandi che la shell legge ed esegue uno dopo l'altro. Per rendere un file di testo un vero script eseguibile sul sistema operativo, è fondamentale seguire uno standard preciso.
La Struttura Anatomica dello Script
Ogni script professionale deve aprirsi con la cosiddetta Shebang (#!/bin/bash) posizionata tassativamente nella primissima riga del file. Questo indica al sistema quale interprete utilizzare per tradurre i comandi sottostanti.
#!/bin/bash # Questo è un commento didattico: la shebang qui sopra è obbligatoria! echo "Hello, Bash!"
Le Due Modalità di Esecuzione
Spesso si genera confusione su come lanciare uno script. In Bash hai due strade principali a tua disposizione:
| Metodo | Comando | Richiede chmod +x? | Descrizione |
|---|---|---|---|
| Standard Professionale | ./mio_script.sh |
SÌ | Usa la Shebang dichiarata nel file per eseguirlo direttamente. |
| Scorciatoia Diretta | bash mio_script.sh |
NO | Avvia esplicitamente Bash passandogli il file. Perfetto per sviluppo rapido. |
Se utilizzi il metodo professionale (./script.sh), segui questo ciclo:
- Crea il file:
touch script.sh - Modifica il file (includi
#!/bin/bashalla riga 1) - Rendilo eseguibile:
chmod +x script.sh - Avvialo:
./script.sh
Ambiente Windows: Sviluppare in Git Bash
Poiché questo corso si appoggia alla didattica su macchine Windows, utilizzeremo l'ambiente simulato Git Bash (fornito con Git per Windows). Lavorare qui introduce dinamiche fondamentali di portabilità e compatibilità.
La Traduzione dei Percorsi (Drive Mapping)
Windows utilizza la sintassi classica delle partizioni (es: C:\Users\Studente\Documenti). Git Bash, lavorando secondo lo standard POSIX, traduce questi percorsi virtualmente:
- Il disco rigido locale
C:diventa/c/ - Il percorso precedente si traduce in:
/c/Users/Studente/Documenti - La cartella personale (Home) può essere abbreviata con la tilde:
~
Su server reali Linux, $USER contiene il nome dell'utente loggato. Su Git Bash Windows, potrebbe risultare completamente vuoto! Usa questa configurazione difensiva:
# Se $USER è vuoto, usa $USERNAME. Se entrambi vuoti, usa whoami UTENTE_ATTUALE=${USER:-$USERNAME} if [ -z "$UTENTE_ATTUALE" ]; then UTENTE_ATTUALE=$(whoami) fi echo "L'utente corrente è: $UTENTE_ATTUALE"
Cheat-Sheet Interattivo (35+ Comandi)
Consulta, filtra e scarica in tempo reale la tabella completa dei principali comandi Bash. Ricerca per nome, descrizione o categoria.
Come si Generano le Variabili Globali?
Se dichiari una variabile all'interno di un terminale (es: MIA_CART="progetti"), quella variabile è locale — esiste solo nel processo in cui è nata. Per renderla globale e farla ereditare da altri script, dobbiamo usare l'istruzione export.
I Tre Livelli di Dichiarazione
| Tipologia | Sintassi | Ambito & Durata |
|---|---|---|
| Locale | MIA_VAR="valore" |
Valida solo nel terminale corrente. Svanisce subito. |
| Globale Temporanea | export WORDLIST="/path" |
Ereditata da script lanciati. Svanisce alla chiusura finestra. |
| Globale Permanente | Dentro ~/.bashrc |
Valida per sempre. Caricata automaticamente. |
# 1. Scrivi l'esportazione in coda al file ~/.bashrc echo 'export WORDLIST="/c/Users/utente/Documenti/words.txt"' >> ~/.bashrc # 2. Ricarica la configurazione per applicare istantaneamente source ~/.bashrc
Sicurezza, Permessi File & Notazione Ottale
In ambiente Linux/POSIX, la sicurezza è governata da una matrice di permessi assegnata a ogni file e cartella. I permessi si dividono in tre classi di utenti:
- Owner (u): Il proprietario del file
- Group (g): Gli utenti del gruppo associato
- Others (o): Tutti gli altri utenti del sistema
Le Tre Operazioni Base
Ogni classe di utenti può avere diritti di Lettura (r), Scrittura (w), ed Esecuzione (x).
| Operazione | Simbolo | File | Directory |
|---|---|---|---|
| Lettura | r |
Leggere il contenuto | Listare i file dentro |
| Scrittura | w |
Modificare il contenuto | Creare/eliminare file dentro |
| Esecuzione | x |
Eseguire come programma | Accedere alla directory |
755= rwx r-x r-x (proprietario esecuzione, gruppo/altri no)644= rw- r-- r-- (solo proprietario scrive)777= rwx rwx rwx (chiunque può fare tutto)700= rwx --- --- (solo proprietario, accesso totale)
# Rendere uno script eseguibile chmod +x script.sh chmod 755 script.sh # Permettere a gruppo e altri di leggere/eseguire chmod 755 file.txt # Accesso solo al proprietario chmod 700 file.txt # Visualizzare permessi dettagliati ls -l
Laboratorio Script Progressivi
Esercizi progressivi per imparare Bash attraverso script pratici e funzionali. Ogni script è presentato in una o più varianti di complessità crescente: copia i codici, modificali e sperimenta!
Script 1: benvenuto.sh — Hello World Personalizzato
Il primo script: dichiarare variabili locali e stampare valori a schermo. Attenzione alla sintassi: in Bash non si mettono spazi intorno al segno = nelle assegnazioni.
Variante Base
Dichiara due variabili, intercetta l'utente di sistema e stampa un messaggio di benvenuto.
#!/bin/bash # Dichiarazione variabili locali (ATTENZIONE: nessun spazio intorno all'uguale '=') NOME="Sviluppatore" CORSO="Bash Base" # Intercettiamo l'utente in modo robusto per Windows/Git Bash: # ${USER:-$USERNAME} significa: usa $USER, se vuoto usa $USERNAME UTENTE_CORRENTE=${USER:-$USERNAME} # Stampe dell'output sul terminale echo "Benvenuto, $NOME!" echo "Utente di sistema corrente: $UTENTE_CORRENTE" echo "Stai seguendo il corso: $CORSO"
Variante Intermedia
Aggiunge il costrutto if per gestire il caso in cui sia $USER che $USERNAME siano vuoti (possibile su alcuni ambienti Windows), e usa $(date) per stampare data e ora correnti.
#!/bin/bash # Dichiarazione variabili locali NOME="Sviluppatore" CORSO="Bash Base" # Intercettiamo l'utente: primo tentativo con ${USER:-$USERNAME} UTENTE_CORRENTE=${USER:-$USERNAME} # if [ -z "..." ] verifica se la stringa è vuota (zero-length) # Se entrambe le variabili d'ambiente sono vuote, usiamo il comando whoami if [ -z "$UTENTE_CORRENTE" ]; then UTENTE_CORRENTE=$(whoami) fi # $(date '+formato') esegue il comando date e ne cattura l'output # %d = giorno, %m = mese, %Y = anno, %H = ore, %M = minuti, %S = secondi DATA_ORA=$(date '+%d/%m/%Y %H:%M:%S') # Stampe dell'output sul terminale echo "═══════════════════════════════════" echo "Benvenuto, $NOME!" echo "Utente di sistema: $UTENTE_CORRENTE" echo "Corso: $CORSO" echo "Data e ora: $DATA_ORA" echo "═══════════════════════════════════"
Copia il codice, salvalo in benvenuto.sh, esegui chmod +x benvenuto.sh, quindi ./benvenuto.sh
Script 2: progetto.sh — Creazione Cartelle Progetto
Chiede all'utente il nome di un progetto via read e crea automaticamente la struttura di cartelle. Usa mkdir -p per creare cartelle annidate senza errori se già esistono.
#!/bin/bash # Intercetta l'utente corrente (compatibile Windows/Git Bash) UTENTE=${USER:-$USERNAME} echo "Benvenuto utente $UTENTE!!" # Richiesta di input testuale: read legge ciò che l'utente digita echo "Inserisci il nome del progetto da creare:" read NOME_PROGETTO echo "Creazione cartella in corso..." # mkdir -p: crea la cartella genitore "Progetti" se non esiste, # e non restituisce errore se la sottocartella esiste già mkdir -p "Progetti/$NOME_PROGETTO" echo "Cartella '$NOME_PROGETTO' creata con successo!" # ls -ld mostra i dettagli di una cartella specifica (non il suo contenuto) ls -ld "Progetti/$NOME_PROGETTO"
Script 3: classifica.sh — Parametri e Costrutti Condizionali
Riceve un numero come argomento da riga di comando e lo classifica. Introduce i parametri posizionali ($1, $#, $0) e i comparatori matematici di Bash.
#!/bin/bash # $# conta quanti argomenti l'utente ha inserito a riga di comando # Se non ne ha inseriti, mostriamo l'uso corretto ed usciamo if [ $# -eq 0 ]; then echo "Errore sintattico. Uso corretto: $0 <numero>" exit 1 fi # $1 è il primo parametro inviato (es: ./classifica.sh 5 → $1 vale 5) numero=$1 # Comparatori per costrutti if-else matematici: # -lt (less than, <) | -eq (equal, ==) | -le (less or equal, <=) if [ "$numero" -lt 0 ]; then echo "negativo" elif [ "$numero" -eq 0 ]; then echo "zero" elif [ "$numero" -le 9 ]; then echo "piccolo" else echo "grande" fi
-lt (less than), -le (less or equal), -eq (equal), -ne (not equal), -gt (greater than), -ge (greater or equal).
Script 4: media.sh — Calcolo Media Aritmetica
Legge voti da un file di testo (uno per riga), calcola la media intera con Bash e poi quella decimale precisa usando awk. Se il file non esiste, ne crea uno di prova.
#!/bin/bash # Verifica se il file dei dati esiste. Se manca, lo creiamo di esempio if [ ! -f voti.txt ]; then echo "File 'voti.txt' non trovato. Inizializzo file di prova..." echo -e "18\n24\n30\n26\n22" > voti.txt fi somma=0 conta=0 # Il ciclo while read legge il file passato in fondo col simbolo '<' while read voto; do # Ignoriamo eventuali righe vuote nel documento [ -z "$voto" ] && continue somma=$((somma + voto)) conta=$((conta + 1)) done < voti.txt # Divisione intera standard di Bash (non supporta decimali) media=$((somma / conta)) echo "Somma dei voti analizzati: $somma" echo "Numero di righe elaborate: $conta" echo "Media (arrotondata all'intero per limite Bash): $media" # RISOLUZIONE DEL LIMITE: integrazione con AWK per calcolo decimale preciso media_precisa=$(awk '{somma+=$1; conta++} END {print somma/conta}' voti.txt) echo "Media reale (con cifre decimali tramite AWK): $media_precisa"
Bash supporta solo aritmetica intera. Per calcoli con decimali è necessario integrare strumenti esterni come awk o bc.
Script 5: cercaparola.sh — Ricerca e Conteggio
Cerca una parola in un file di testo e conta le occorrenze. Due varianti: una base con input interattivo, una avanzata che sfrutta la variabile globale $WORDLIST.
Variante Base
Chiede all'utente parola e file da cercare tramite read -p. Usa grep -o per contare le singole occorrenze.
#!/bin/bash # Chiediamo all'utente cosa cercare e dove read -p "Inserisci la parola da cercare: " PAROLA read -p "Inserisci il file dove cercare: " FILE # Verifica che il file esista prima di procedere if [ ! -f "$FILE" ]; then echo "Errore: file non trovato!" exit 1 fi # grep -o stampa solo le corrispondenze (una per riga), wc -l le conta CONTEGGIO=$(grep -o "$PAROLA" "$FILE" | wc -l) echo "La parola '$PAROLA' appare $CONTEGGIO volte in $FILE"
Variante Avanzata (con $WORDLIST)
Usa la variabile globale $WORDLIST (definita con export nella sezione 4) come dizionario sorgente. Se la variabile non è stata impostata, crea un file locale di fallback. Accetta la parola sia da argomento che da input interattivo.
#!/bin/bash # 1. Sicurezza preventiva: la variabile globale $WORDLIST esiste? if [ -z "$WORDLIST" ]; then echo "ATTENZIONE: La variabile globale \$WORDLIST non risulta valorizzata!" echo "Abilitazione fallback locale per impedire l'arresto dello script..." WORDLIST="./words.txt" # Se non esiste neanche il file locale, ne generiamo uno al volo if [ ! -f "$WORDLIST" ]; then echo -e "casa\nalbero\ntavolo\nbash\ncorso\nsviluppatore\nsistema" > "$WORDLIST" fi fi echo "Dizionario sorgente caricato da: $WORDLIST" # 2. Controllo degli argomenti del terminale if [ $# -eq 0 ]; then # Se l'utente non ha passato parametri, li chiediamo con 'read' read -p "Inserisci la parola da cercare: " parola else # Altrimenti prendiamo il primo argomento passato parola=$1 fi # 3. Ricerca effettiva (-i = case-insensitive) echo "Corrispondenze trovate:" grep -i "$parola" "$WORDLIST" # 4. Conteggio complessivo delle righe trovate tramite flag '-c' trovate=$(grep -i -c "$parola" "$WORDLIST") echo "Totale righe corrispondenti trovate: $trovate"
Per usare $WORDLIST senza fallback, impostala prima con: export WORDLIST="/percorso/al/dizionario.txt" (vedi sezione 4 — Variabili Globali).
Script 6: backup_progetti.sh — Archiviazione con Timestamp
Crea una copia di backup della cartella Progetti aggiungendo la data e ora correnti al nome dell'archivio. Combina date, if, mkdir -p e cp -r.
#!/bin/bash SORGENTE="Progetti" DESTINAZIONE="Backup" # Definiamo la stringa temporale con anno, mese, giorno, ore e minuti DATA=$(date +%Y-%m-%d_%H-%M) # Verifichiamo l'esistenza della sorgente con -d (directory exists) if [ ! -d "$SORGENTE" ]; then echo "Errore critico: La cartella sorgente '$SORGENTE' non esiste su disco." exit 1 fi # Genera la cartella di backup se mancante mkdir -p "$DESTINAZIONE" echo "Avvio dell'archiviazione dati..." # Copia ricorsiva (-r) della sorgente, rinominando con la data corrente cp -r "$SORGENTE" "$DESTINAZIONE/backup_progetti_$DATA" echo "Operazione conclusa con successo. Archivio registrato in: $DESTINAZIONE/backup_progetti_$DATA"