HOWTO · Linux
Leggere un file linea per linea utilizzando Bash
Usiamo il comando read in Bash per leggere un file linea per linea.
In questa pagina
Bash può elaborare un file di testo una riga alla volta usando il comando read all’interno di un ciclo while. In questo modo l’input viene elaborato in streaming e lo script non deve conservare in memoria l’intero file. Usa IFS= per mantenere gli spazi iniziali e finali, -r per preservare le barre inverse e racchiudi tra virgolette "$line" ogni volta che espandi il valore.
Leggere un file riga per riga con un ciclo while
Un ciclo affidabile legge dal file tramite la redirezione dell’input. Anche la condizione || [[ -n $line ]] consente di elaborare l’ultima riga quando il file non termina con un carattere di nuova riga. Il ciclo elabora il file in streaming e mantiene il totale parziale nella shell corrente.
L’esempio completo qui sotto crea i propri dati numerici, stampa ogni valore e somma tutti e sei i numeri: 1, 5, 6, 7, 8 e 10. Il totale è 37. Le etichette e le frasi visualizzate nell’esempio restano in inglese: l’output elenca ciascun valore e riporta la somma totale, 37.
#!/usr/bin/env bash
set -u
file=$(mktemp)
trap 'rm -f "$file"' EXIT
printf '%s\n' 1 5 6 7 8 10 > "$file"
sum=0
printf 'The numbers in the file are:\n'
while IFS= read -r line || [[ -n $line ]]; do
printf '%s\n' "$line"
sum=$((sum + line))
done < "$file"
printf 'The sum of the numbers in the file is:%s\n' "$sum"
The numbers in the file are:
1
5
6
7
8
10
The sum of the numbers in the file is:37
La redirezione dell’input mantiene il ciclo nella shell corrente, quindi le modifiche, come il totale parziale, restano disponibili anche dopo la sua esecuzione. Evita espansioni senza virgolette come $line: la suddivisione in parole e l’espansione dei nomi di percorso possono modificarne il contenuto.
Suddividere ogni riga in campi
Per suddividere i record usando un delimitatore, leggi prima ogni riga senza modificarla e poi assegna i campi alle variabili. In una lettura basata su un delimitatore, l’ultima variabile di read riceve i campi rimanenti. Questo esempio crea ed elabora tutti e cinque i record: Rohit-10, Harish-30, Manish-50, Kapil-10 e Anish-20. La condizione per l’ultima riga elabora anche un record finale non vuoto quando il file non termina con un carattere di nuova riga.
#!/usr/bin/env bash
set -u
file=$(mktemp)
trap 'rm -f "$file"' EXIT
printf '%s\n' 'Rohit-10' 'Harish-30' 'Manish-50' 'Kapil-10' 'Anish-20' > "$file"
while IFS= read -r line || [[ -n $line ]]; do
IFS=- read -r name earnings <<< "$line"
printf '%s has made earnings of %s pounds today!\n' "$name" "$earnings"
done < "$file"
Rohit has made earnings of 10 pounds today!
Harish has made earnings of 30 pounds today!
Manish has made earnings of 50 pounds today!
Kapil has made earnings of 10 pounds today!
Anish has made earnings of 20 pounds today!
Qui IFS=- imposta il trattino come delimitatore per la lettura che assegna i campi. Con due variabili, name riceve il testo prima del primo trattino e earnings riceve il resto. Quando stampi i valori, racchiudi le variabili tra virgolette affinché il loro contenuto venga passato come singolo valore.
Scegliere un altro metodo per leggere file in Bash
Usa lo schema while IFS= read -r line quando vuoi elaborare ogni riga man mano che arriva o quando il file potrebbe essere più grande della memoria disponibile. Per un file normale, redirigilo direttamente nel ciclo: eseguire cat tramite la sostituzione di processo non offre vantaggi. La sostituzione di processo può essere utile se il ciclo deve leggere l’output generato da un comando invece di un file.
Se la tua installazione di Bash include mapfile, puoi usarlo per caricare le righe del file in un array, per esempio con mapfile -t lines < "$file". Scegli questo metodo quando i passaggi successivi richiedono l’accesso tramite indice o più letture delle righe e l’intero file entra in memoria. L’opzione -t rimuove il carattere di nuova riga finale da ogni riga. La disponibilità dipende dall’installazione di Bash; se ti serve un metodo più ampiamente applicabile, usa il ciclo che elabora il file in streaming.