Я намагаюся пропустити дві послідовності в одному циклі в оболонці, як нижче:
#!/bin/bash
for i in (1..15) and (20..25) ;
do
echo $i
......
.....other process
done
будь-яка ідея, як я можу цього досягти?
Я намагаюся пропустити дві послідовності в одному циклі в оболонці, як нижче:
#!/bin/bash
for i in (1..15) and (20..25) ;
do
echo $i
......
.....other process
done
будь-яка ідея, як я можу цього досягти?
Відповіді:
Для цього вам потрібно лише розширення дужок
$ for n in {1..3} {200..203}; do echo $n; done
1
2
3
200
201
202
203
Ми можемо передати список for
( ).for i in x y z; do stuff "$i"; done
Тож ось, брекети {
}
отримують оболонку, щоб розширити ваші послідовності до списку. Вам потрібно лише поставити пробіл між ними, оскільки оболонка розбиває списки аргументів на них.
echo
цифри
touch
файли, вони можуть просто зробити touch {1..15}.txt {20..25}.txt
, тут не потрібна петля. Але звичайно, якщо це кілька дій на одне число - ОК, це може використовувати цикл.
Можна також використати seq
( друкувати послідовність чисел ), ось два еквівалентні приклади:
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
Якщо це сценарій, для повторюваних завдань можна використовувати функції:
#!/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"
Відповідь Žanna в і відповідь pa4080 ігрових обидва гарні , і я б , ймовірно , піти з одним з них у більшості випадків. Можливо, це само собою зрозуміло, але задля повноти я все одно скажу: Ви можете завантажити кожне значення в масив, а потім перевести цикл на масив. Наприклад:
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
Відповідь Zanna абсолютно правильна і добре підходить для bash, але ми можемо вдосконалити це ще більше, не використовуючи цикл.
printf "%d\n" {1..15} {20..25}
Поведінка printf
такої, що якщо кількість значень ARGUMENTS
більше, ніж контроль у форматі 'FORMAT STRING'
, то printf
вони розділять усі ARGUMENTS
на рівні фрагменти і продовжуватимуть прилаштовувати їх до рядка формату знову і знову, поки не закінчується ARGUMENTS
список.
Якщо ми прагнемо портативності, ми можемо використовувати це printf "%d\n" $(seq 1 15) $(seq 20 25)
замість цього
Візьмемо це далі і веселіше. Скажімо, ми хочемо виконати дію, а не просто друкувати номери. Створення файлів із цієї послідовності чисел ми могли легко зробити touch {1..15}.txt {20..25}.txt
. Що робити, якщо ми хочемо, щоб відбулося багато речей? Ми також могли б зробити щось подібне:
$ printf "%d\n" {1..15} {20..25} | xargs -I % bash -c 'touch "$1.txt"; stat "$1.txt"' sh %
Або якщо ми хочемо зробити його старошкільним стилем:
printf "%d\n" {1..15} {20..25} | while read -r line; do
touch "$line".txt;
stat "$line".txt;
rm "$line".txt;
done
Якщо ми хочемо зробити сценарій рішення, яке працює з оболонками, які не мають розширення дужок (на що {1..15} {20..25}
покладається), ми можемо написати простий цикл 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
Звичайно, це рішення є більш багатослівним, деякі речі можна скоротити, але воно працює. Випробувано з ksh
, dash
, mksh
і, звичайно ж bash
.
Але якщо ми хотіли зробити певну певну певну петлю (з будь-якої причини, можливо, не просто друкуючи, а й роблячи щось із цими номерами), ми також можемо це зробити (в основному версія портативного рішення на C-циклі):
last=15; for (( i=1; i<=last;i++ )); do printf "%d\n" "$i"; [[ $i -eq $last ]] && ! [[ $i -eq 25 ]] && { i=19;last=25;} ;done
Або в більш читаному форматі:
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
Просто тому, що ми можемо ось рішення Python
$ python3 -c 'print("\n".join([str(i) for i in (*range(1,16),*range(20,26))]))'
Або з трохи шкаралупи:
bash-4.3$ python3 << EOF
> for i in (*range(16),*range(20,26)):
> print(i)
> EOF
touch $(printf "%d\n" {1..15} {20..25})
:-)
bash
вам $()
там навіть не потрібно , просто touch {1..15}.txt {20..25}.txt
:) Але, звичайно, ми могли б використовувати printf "%d\n
{1..15} {20..25} `, xargs
якщо б хотіли зробити більше, ніж просто touch
файли. Є багато способів зробити речі, і це робить сценарій так веселим!