Corso Linux / Creare uno script Bash con variabili, condizioni e cicli
Uno script di shell raccoglie comandi e controllo del flusso in un programma riutilizzabile. Per iniziare con Bash, proteggi le espansioni delle variabili con le virgolette, verifica gli argomenti e controlla lo stato di uscita mentre provi un piccolo script completo.
In questa lezione salvi il programma in un file e lo esegui. Per variabili, operatori e stati di uscita consulta la spiegazione del flusso di esecuzione della shell; per i limiti relativi a errori, percorsi e concorrenza consulta la lezione sugli errori Bash e le operazioni sicure sui file (in inglese).
Scegliere Bash e preparare la directory di lavoro
La lezione è pensata per Bash su Ubuntu e Rocky Linux. Funzioni come [[ ... ]] e gli array non sono portabili a qualsiasi sh: non avviare uno script Bash con sh script.sh. Controlla la disponibilità con bash --version e salva i file con terminatori di riga LF, cioè il carattere di avanzamento riga.
Esegui il blocco seguente in Bash, in un ambiente di laboratorio. Crea una directory temporanea nuova nella tua home e due file di esempio. La catena di && interrompe il blocco al primo errore: se mktemp o cd falliscono, non prosegue creando file nella directory precedente. Verifica che il blocco sia riuscito e controlla pwd prima di continuare; usa lo stesso terminale per mantenere la directory corrente.
lab=$(mktemp -d "$HOME/linux-script-lab.XXXXXX") &&
cd "$lab" &&
mkdir "sample files" &&
printf "one\n" > "sample files/alpha.txt" &&
printf "two\n" > "sample files/beta.txt"
Creare lo script completo ed eseguirlo
Questo blocco crea list-files.sh nella directory corrente: accertati che sia quella nuova del laboratorio, perché la redirezione sostituisce un eventuale file con lo stesso nome. Il programma accetta un solo argomento, verifica che sia una directory e stampa i nomi dei file ordinari trovati. Lo script creato legge i nomi senza modificare i file; il blocco che lo prepara, invece, scrive il file dello script.
cat > list-files.sh <<'EOF'
#!/usr/bin/env bash
if (( $# != 1 )); then
printf "Usage: %s DIRECTORY\n" "$0" >&2
exit 2
fi
directory=$1
if [[ ! -d "$directory" ]]; then
printf "Not a directory: %s\n" "$directory" >&2
exit 1
fi
count=0
for path in "$directory"/*; do
[[ -f "$path" ]] || continue
printf "%s\n" "${path##*/}"
count=$((count + 1))
done
printf "files=%s\n" "$count"
EOF
bash -n list-files.sh
bash list-files.sh "sample files"
Con i due file iniziali attenditi alpha.txt, beta.txt e files=2. L'ordine dei nomi può dipendere dalle impostazioni locali. bash -n controlla soltanto la sintassi, senza eseguire il programma: non verifica percorsi e permessi. Controllane lo stato prima dell'esecuzione; le ultime due righe del blocco sono comandi separati e un controllo fallito non impedisce automaticamente al successivo di partire.
La prima riga #!/usr/bin/env bash è lo shebang, che seleziona l'interprete per l'avvio diretto. Non è un prompt da anteporre ai comandi. env cerca Bash nel PATH: usa un ambiente attendibile.
Capire variabili, virgolette e nomi di file
L'assegnazione directory=$1 non ammette spazi intorno al segno di uguale. $1 è il primo argomento. Quando usi il valore in "$directory", le virgolette doppie mantengono un percorso con spazi come un unico argomento. Le virgolette singole impediscono normalmente l'espansione; quelle doppie consentono l'espansione dei parametri evitando la separazione in parole e l'espansione dei nomi di file. Non serve reinterpretare l'input come un comando con eval.
In "$directory"/* la parte relativa alla directory è protetta, mentre l'asterisco rimane disponibile per l'espansione dei nomi. Con le impostazioni predefinite di Bash, un pattern senza corrispondenze può restare letterale: [[ -f "$path" ]] || continue lo salta se non identifica un file ordinario. Il pattern esclude i nomi che iniziano con un punto e non esplora le sottodirectory. Un collegamento simbolico a un file ordinario può superare il controllo -f. Opzioni come dotglob, nullglob e failglob possono cambiare questo comportamento: per confrontare i risultati usa Bash con le impostazioni predefinite.
Il delimitatore tra apici in <<'EOF' impedisce alla shell che crea il file di espandere subito $1, $path e gli altri parametri del testo. Le espansioni avvengono quando esegui lo script generato. Per i dettagli consulta il manuale Bash sull'espansione dei parametri.
Leggere argomenti, condizioni, cicli e stato di uscita
| Sintassi | Significato |
|---|---|
| $# / $1 | Numero di argomenti / primo argomento |
| [[ -d ... ]] | Verifica che il percorso sia una directory |
| for ...; do ...; done | Applica il corpo a ciascun elemento espanso |
| ${path##*/} | Rimuove il prefisso fino all'ultima barra, lasciando il nome |
| exit 0 / 1 / 2 | Successo / destinazione non valida / uso errato in questo esempio |
Il controllo iniziale su $# richiede esattamente un argomento: se manca o ce ne sono troppi, stampa l'uso sullo standard error e termina con 2. Se il percorso non è una directory, termina con 1. Il ciclo incrementa count per ogni elemento che supera il controllo. Se l'ultimo printf riesce, lo script termina con stato 0. I significati di 1 e 2 sono convenzioni scelte dal programma, non una classificazione universale di tutti i comandi.
$? contiene lo stato del comando appena terminato: leggilo subito, prima di eseguire altro. Nel blocco seguente la prima chiamata deve produrre un messaggio d'uso e exit=2; quella con missing-directory deve produrre un errore e exit=1. Verifica che questo nome non esista già nel laboratorio. Le ultime righe aggiungono il permesso di esecuzione al proprietario e avviano il programma direttamente.
bash list-files.sh
printf "exit=%s\n" "$?"
bash list-files.sh missing-directory
printf "exit=%s\n" "$?"
chmod u+x list-files.sh
./list-files.sh "sample files"
Questo è un esercizio sul controllo del flusso, non uno strumento di inventario affidabile per directory non accessibili o modificate durante l'esecuzione. Il solo controllo -d non garantisce che tutti i nomi siano leggibili: una directory non esplorabile può anche portare a un conteggio zero. Inoltre un nome contenente un ritorno a capo può occupare più righe nell'output. Non interpretare files=0 come prova universale che una directory sia vuota.
Cambiare una condizione alla volta
- Esegui
bash list-files.sh "sample files"e verifica i due nomi efiles=2. - Crea soltanto il nuovo file con
printf 'three\n' > "sample files/gamma.txt". Ripeti l'esecuzione e verificafiles=3. - Rimuovi soltanto il file aggiunto con
rm -- "sample files/gamma.txt". Ripeti la prova e verifica il ritorno afiles=2. - Crea una directory vuota con
mkdir "empty files"ed eseguibash list-files.sh "empty files": attenditifiles=0e stato 0. Con un percorso inesistente attenditi il messaggio di errore e stato 1; senza argomenti o con due argomenti attenditi lo stato 2.
Se dopo una modifica su Windows compaiono errori con bash\r o ^M, controlla i terminatori di riga. CRLF indica la coppia ritorno carrello e avanzamento riga; LF usa soltanto il secondo carattere. In VS Code puoi selezionare CRLF nella barra di stato e cambiare in LF, quindi salvare.
In un laboratorio con GNU sed puoi anche usare il blocco seguente. Prima verifica che list-files.sh.crlf-backup non esista: deve essere una copia nuova, non un backup precedente da sovrascrivere. Se cp fallisce o chiede una conferma che rifiuti, fermati e non eseguire sed. I comandi sono separati e non interrompono automaticamente il blocco in caso di errore. Specifica soltanto il file creato in questa prova.
cp -i -- list-files.sh list-files.sh.crlf-backup
sed -i 's/\r$//' list-files.sh
bash -n list-files.sh
bash list-files.sh "sample files"
La sostituzione rimuove un carattere CR soltanto alla fine di ciascuna riga. Il controllo sintattico deve terminare senza output con stato 0; se restano soltanto i due file iniziali, attenditi di nuovo files=2. Per annullare la conversione, verifica il contenuto della copia e ripristinala con cp -i -- list-files.sh.crlf-backup list-files.sh; poi controlla nuovamente il formato prima di eseguire.
bash list-files.sh legge lo script con Bash anche senza il permesso di esecuzione, purché il file sia leggibile. L'avvio con ./list-files.sh richiede anche permessi e interprete adatti; opzioni del file system come noexec possono impedirlo. I test con Git Bash su Windows verificano logica, argomenti e conversione del testo, ma non dimostrano i permessi di esecuzione di un file system Linux. Prima di ripulire, controlla il percorso e rimuovi soltanto i file di questo laboratorio.




