<Precedenti | Contenuti | Succ.>
Raggruppa comandi e sottoshell
bash consente di raggruppare i comandi. Questo può essere fatto in due modi: con un comando di gruppo sia presso una sottoguscioEcco alcuni esempi della sintassi di ciascuno:
Comando di gruppo:
{ comando1; comando2; [comando3; ...] }
Sottoguscio:
(comando1; comando2; [comando3;...])
Le due forme differiscono in quanto un comando di gruppo racchiude i suoi comandi tra parentesi graffe e una subshell utilizza le parentesi tonde. È importante notare che, a causa del modo in cui bash implementa comandi di gruppo, le parentesi graffe devono essere separate dai comandi da uno spazio e l'ultimo comando deve essere terminato con un punto e virgola o una nuova riga prima della parentesi graffa di chiusura.
A cosa servono quindi i comandi di gruppo e le subshell? Sebbene presentino una differenza importante (che approfondiremo tra poco), entrambi vengono utilizzati per gestire il reindirizzamento. Consideriamo un segmento di script che esegue reindirizzamenti su più comandi:
ls -l > output.txt
echo "Elenco di foo.txt" >> output.txt cat foo.txt >> output.txt
ls -l > output.txt
echo "Elenco di foo.txt" >> output.txt cat foo.txt >> output.txt
Questo è abbastanza semplice. Tre comandi il cui output viene reindirizzato a un file denominato output.txtUtilizzando un comando di gruppo, potremmo codificarlo come segue:
{ ls -l; echo "Elenco di foo.txt"; cat foo.txt; } > output.txt
{ ls -l; echo "Elenco di foo.txt"; cat foo.txt; } > output.txt
L'utilizzo di una subshell è simile:
(ls -l; echo "Elenco di foo.txt"; cat foo.txt) > output.txt
(ls -l; echo "Elenco di foo.txt"; cat foo.txt) > output.txt
Utilizzando questa tecnica ci siamo risparmiati un po' di digitazione, ma dove un comando di gruppo o una subshell danno il meglio di sé è con le pipeline. Quando si costruisce una pipeline di comandi, è spesso utile combinare i risultati di diversi comandi in un unico flusso. I comandi di gruppo e le subshell semplificano questa operazione:
{ ls -l; echo "Elenco di foo.txt"; cat foo.txt; } | lpr
{ ls -l; echo "Elenco di foo.txt"; cat foo.txt; } | lpr
Qui abbiamo combinato l'output dei nostri tre comandi e li abbiamo convogliati nell'input di LPR per produrre un rapporto stampato.
Nello script che segue, useremo i comandi groups e analizzeremo diverse tecniche di programmazione che possono essere impiegate in combinazione con gli array associativi. Questo script, chiamato matrice-2, quando gli viene fornito il nome di una directory, stampa un elenco dei file nella directory insieme ai nomi del proprietario del file e del gruppo proprietario. Alla fine dell'elenco, lo script stampa un conteggio del numero di file appartenenti a ciascun proprietario e gruppo. Qui vediamo i risultati (condensati per brevità) quando allo script viene fornita la directory.
/usr/bin:
[io@linuxbox~]$ array-2 /usr/bin | ||
/usr/bin/2to3-2.6 | radice | radice |
/usr/bin/2to3 | radice | radice |
/usr/bin/a2p | radice | radice |
/usr/bin/abrowser | radice | radice |
/usr/bin/aconnect | radice | radice |
/usr/bin/acpi_fakekey | radice | radice |
/usr/bin/acpi_listen | radice | radice |
/usr/bin/aggiungi-repository-apt | radice | radice |
. | ||
. | ||
. | ||
/usr/bin/zipgrep | radice | radice |
/usr/bin/zipinfo | radice | radice |
/usr/bin/zipnote | radice | radice |
/usr/bin/zip | radice | radice |
/usr/bin/zipsplit /usr/bin/zjsdecode /usr/bin/zsoelim | radice radice radice | radice radice radice | |
Proprietari del file: demone: 1 | File) | ||
radice: 1394 | File) |
Proprietari del gruppo di file: crontab : 1 file(s) daemon : 1 file(s) lpadmin : 1 file(s) mail : 4 file(s) mlocate : 1 file(s) root : 1380 file(s) shadow : 2 file(s) ssh : 1 file(s)
tty : 2 file
utmp : 2 file
#! / Bin / bash
#! / Bin / bash
# array-2: usa gli array per contare i proprietari dei file
dichiara -A file file_group file_owner gruppi proprietari se [[ ! -d "$1" ]]; quindi
echo "Utilizzo: array-2 dir" >&2 exit 1
fi
per i in "$1"/*; fai proprietario=$(stat -c %U "$i") gruppo=$(stat -c %G "$i") file["$i"]="$i" proprietario_file["$i"]=$proprietario gruppo_file["$i"]=$gruppo ((++proprietari[$proprietario])) ((++gruppi[$gruppo]))
fatto
# Elenca i file raccolti
{ per i in "${files[@]}"; fai printf "%-40s %-10s %-10s\n" \
"$i" ${file_owner["$i"]} ${file_group["$i"]} fatto } | ordina
# array-2: usa gli array per contare i proprietari dei file
dichiara -A file file_group file_owner gruppi proprietari se [[ ! -d "$1" ]]; quindi
echo "Utilizzo: array-2 dir" >&2 exit 1
fi
per i in "$1"/*; fai proprietario=$(stat -c %U "$i") gruppo=$(stat -c %G "$i") file["$i"]="$i" proprietario_file["$i"]=$proprietario gruppo_file["$i"]=$gruppo ((++proprietari[$proprietario])) ((++gruppi[$gruppo]))
fatto
# Elenca i file raccolti
{ per i in "${files[@]}"; fai printf "%-40s %-10s %-10s\n" \
"$i" ${file_owner["$i"]} ${file_group["$i"]} fatto } | ordina
Ecco un elenco (con i numeri di riga) dello script:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
27
28
29
30
31
32
33
34
35
36
37
38
39
40
eco
eco
# Proprietari dell'elenco
echo "Proprietari del file:"
{ per i in "${!owners[@]}"; fai
printf "%-10s: %5d file\n" "$i" ${owners["$i"]} fatto } | ordina
eco
# Elenca gruppi
echo "Proprietari del gruppo di file:"
{ per i in "${!groups[@]}"; fai
printf "%-10s: %5d file\n" "$i" ${groups["$i"]} fatto } | ordina
# Proprietari dell'elenco
echo "Proprietari del file:"
{ per i in "${!owners[@]}"; fai
printf "%-10s: %5d file\n" "$i" ${owners["$i"]} fatto } | ordina
eco
# Elenca gruppi
echo "Proprietari del gruppo di file:"
{ per i in "${!groups[@]}"; fai
printf "%-10s: %5d file\n" "$i" ${groups["$i"]} fatto } | ordina
Diamo un'occhiata ai meccanismi di questo script:
Linea 5: Gli array associativi devono essere creati con dichiarare comando utilizzando il -A
opzione. In questo script creiamo cinque array come segue:
files contiene i nomi dei file nella directory, indicizzati per nome file file_group contiene il proprietario del gruppo di ciascun file, indicizzato per nome file file_owner contiene il proprietario di ciascun file, indicizzato per nome file groups contiene il numero di file appartenenti al gruppo indicizzato owners contiene il numero di file appartenenti al proprietario indicizzato
Righe 7-10: verifica che sia stato passato un nome di directory valido come parametro posizionale. In caso contrario, viene visualizzato un messaggio di utilizzo e lo script termina con uno stato di uscita pari a 1.
Righe 12-20: Esegui un ciclo tra i file nella directory. Utilizzando il stat comando, le righe 13 e 14 estraggono i nomi del proprietario del file e del proprietario del gruppo e assegnano i valori ai rispettivi array (righe 16, 17) utilizzando il nome del file come indice dell'array. Allo stesso modo, il nome del file stesso viene assegnato all'array file array (riga 15).
Righe 18-19: Il numero totale di file appartenenti al proprietario del file e al proprietario del gruppo viene incrementato di uno.
Righe 22-27: L'elenco dei file viene generato. Questo viene fatto utilizzando l'espansione del parametro "${array[@]}", che espande l'intero elenco di elementi dell'array, trattando ogni elemento come una parola separata. Questo consente la possibilità che un nome di file possa contenere spazi incorporati. Si noti inoltre che l'intero ciclo è racchiuso tra parentesi graffe, formando così un comando di gruppo. Ciò consente di inviare l'intero output del ciclo al sorta comando. Ciò è necessario perché l'espansione degli elementi dell'array non è ordinata.
Righe 29-40: Questi due cicli sono simili al ciclo dell'elenco dei file, tranne per il fatto che utilizzano "${!
espansione array[@]}" che si espande nell'elenco degli indici dell'array anziché nell'elenco degli elementi dell'array.