Sto cercando di scorrere due sequenze nello stesso loop nella mia shell come di seguito:
#!/bin/bash
for i in (1..15) and (20..25) ;
do
echo $i
......
.....other process
done
qualche idea di come posso raggiungere questo obiettivo?
Sto cercando di scorrere due sequenze nello stesso loop nella mia shell come di seguito:
#!/bin/bash
for i in (1..15) and (20..25) ;
do
echo $i
......
.....other process
done
qualche idea di come posso raggiungere questo obiettivo?
Risposte:
Per questo è necessario solo un ampliamento del supporto
$ for n in {1..3} {200..203}; do echo $n; done
1
2
3
200
201
202
203
Possiamo passare un elenco a for( ).for i in x y z; do stuff "$i"; done
Quindi, qui, le parentesi graffe { }ottengono la shell per espandere le sequenze in un elenco. Devi solo mettere uno spazio tra di loro, poiché la shell divide gli elenchi di argomenti su quelli.
echoi numeri
touchfile, possono semplicemente fare touch {1..15}.txt {20..25}.txt, non è necessario alcun ciclo qui. Ma ovviamente se si tratta di più azioni sullo stesso numero - OK, potrebbe usare un ciclo.
In alternativa possiamo usare seq( stampare una sequenza di numeri ), qui ci sono due esempi equivalenti:
for i in `seq 1 3` `seq 101 103`; do echo $i; done
for i in $(seq 1 3) $(seq 101 103); do echo $i; done
Se si tratta di uno script, per attività ripetitive, è possibile utilizzare le funzioni:
#!/bin/bash
my_function() { echo "$1"; }
for i in {1..3}; do my_function "$i"; done
for i in {101..103}; do my_function "$i"; done
#!/bin/bash
my_function() { for i in `seq $1 $2`; do echo "$i"; done; }
my_function "1" "3"
my_function "101" "103"
La risposta di Zanna e la risposta di pa4080 sono entrambe buone e probabilmente andrei con una di esse nella maggior parte dei casi. Forse è ovvio, ma per completezza, lo dirò comunque: è possibile caricare ciascun valore in un array e quindi passare in rassegna l'array. Per esempio:
the_array=( 1 2 3 4 5 6 7 8 9 10 20 21 22 23 24 25 )
for i in "${the_array[@]}";
do
echo $i
done
La risposta di Zanna è assolutamente corretta e adatta per bash, ma possiamo migliorarla ancora di più senza utilizzare un loop.
printf "%d\n" {1..15} {20..25}
Il comportamento di printfè tale che se il numero di ARGUMENTSè maggiore dei controlli di formato in 'FORMAT STRING', allora printfsi divideranno tutti ARGUMENTS in blocchi uguali e continueranno ad adattarli più volte alla stringa di formato fino a quando non si esaurisce l' ARGUMENTSelenco.
Se stiamo cercando la portabilità, possiamo printf "%d\n" $(seq 1 15) $(seq 20 25)invece utilizzare
Prendiamo questo ulteriore e più divertente. Supponiamo di voler eseguire un'azione anziché semplicemente stampare numeri. Per creare file da quella sequenza di numeri, potremmo facilmente farlo touch {1..15}.txt {20..25}.txt. E se vogliamo che accadano più cose? Potremmo anche fare qualcosa del genere:
$ printf "%d\n" {1..15} {20..25} | xargs -I % bash -c 'touch "$1.txt"; stat "$1.txt"' sh %
O se vogliamo renderlo in stile vecchia scuola:
printf "%d\n" {1..15} {20..25} | while read -r line; do
touch "$line".txt;
stat "$line".txt;
rm "$line".txt;
done
Se vogliamo creare una soluzione di script che funzioni con shell che non hanno espansione di controvento (che è ciò {1..15} {20..25}su cui si basa), possiamo scrivere un semplice ciclo while:
#!/bin/sh
start=$1
jump=$2
new_start=$3
end=$4
i=$start
while [ $i -le $jump ]
do
printf "%d\n" "$i"
i=$((i+1))
if [ $i -eq $jump ] && ! [ $i -eq $end ];then
printf "%d\n" "$i"
i=$new_start
jump=$end
fi
done
Naturalmente questa soluzione è più dettagliata, alcune cose potrebbero essere abbreviate, ma funziona. Testato con ksh, dash, mksh, e, naturalmente bash.
Ma se volessimo creare un loop bash specifico (per qualsiasi motivo, forse non solo stampare ma anche fare qualcosa con quei numeri), possiamo anche farlo (fondamentalmente versione C-loop della soluzione portatile):
last=15; for (( i=1; i<=last;i++ )); do printf "%d\n" "$i"; [[ $i -eq $last ]] && ! [[ $i -eq 25 ]] && { i=19;last=25;} ;done
O in un formato più leggibile:
last=15
for (( i=1; i<=last;i++ ));
do
printf "%d\n" "$i"
[[ $i -eq $last ]] && ! [[ $i -eq 25 ]] && { i=19;last=25;}
done
bash-4.3$ time bash -c 'printf "%d\n" {0..50000}>/dev/null'
real 0m0.196s
user 0m0.124s
sys 0m0.028s
bash-4.3$ time bash -c 'for i in {1..50000}; do echo $i > /dev/null; done'
real 0m1.819s
user 0m1.328s
sys 0m0.476s
bash-4.3$ time bash -c ' i=0;while [ $i -le 50000 ]; do echo $i>/dev/null; i=$((i+1)); done'
real 0m3.069s
user 0m2.544s
sys 0m0.500s
bash-4.3$ time bash -c 'for i in $(seq 1 50000); do printf "%d\n" > /dev/null; done'
real 0m1.879s
user 0m1.344s
sys 0m0.520s
Solo perché possiamo ecco la soluzione Python
$ python3 -c 'print("\n".join([str(i) for i in (*range(1,16),*range(20,26))]))'
O con un po 'di shell:
bash-4.3$ python3 << EOF
> for i in (*range(16),*range(20,26)):
> print(i)
> EOF
touch $(printf "%d\n" {1..15} {20..25}):-)
bashte non hai nemmeno bisogno $()lì, solo touch {1..15}.txt {20..25}.txt :) Ma ovviamente potremmo usare printf "%d\n{1..15} {20..25} `con xargsse volessimo fare più di un semplice touchfile. Ci sono molti modi per fare le cose e questo rende lo script così divertente!