我正在尝试在外壳程序的同一循环中遍历两个序列,如下所示:
#!/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
任何想法我怎么能做到这一点?
Answers:
您只需要大括号扩展即可
$ 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
因此,在这里,花括号{
}
使外壳将序列扩展为列表。您只需要在它们之间放置一个空格,因为shell会拆分这些参数的列表。
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"
Zanna的答案和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
。
但是,如果我们想创建特定于循环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
,xargs
那么当然可以使用{1..15} {20..25}` touch
。有许多种做事的方法,它使编写脚本变得如此有趣!