最近忽然发现,自己shell 中的循环,似乎除了while read id
以外,忘得一干二净了。
鼎鼎有名的for,自然是每种语言都不可或缺的。
在shell 中,存在两种风格的for 语句。
第一种:
for var in list
do
commands
done
当list 中的元素包含特殊字符或空格时,可以直接使用 双引号 分割每个元素,或者用转义字符转义。
比如:
$ for i in sad ' asd' dasd \\t;do echo -e $i;done
sad
asd
dasd
我们还可以借用{a..b}
,实现数字的批量获取:
$ for i in {1..100}; do echo $i >> test.txt; done
$ tail test.txt
91
92
93
94
95
96
97
98
99
100
因为for 循环需要输入的是一个列表元素,因此,如果尝试直接对文件操作:
$ for i in test.txt
> do echo $i ; done
test.txt
我们可以利用shell 命令替换的语法(找一期详细介绍一下),比如,我们可以使用反引号(也就是md 语法中代码片段的那个符号),相当于命令在执行时,先完成命令替换中的命令,接着用其结果,作为另一个命令的输入:
$ for i in `head test.txt`; do echo $i; done
1
2
3
4
5
6
7
8
9
10
shell 中的for 循环,需要使用双括号进行选择,其中的结构和C 中的for 非常类似,都是三段式:
for ((a=1; a<10; a++)); do echo $a; done
还可以同时定义多个变量,但三段式中的条件判断,只能设置某一个条件:
for ((a=1, b=10; a<10; a++, b--)); do echo $a' '$b; done
同样,shell 也提供了两种使用while 的风格。
第一种while 风格,跟其他编程语言类似。
a=4
while (( a>0 )); do echo $a; a=$(( --a )); done
4
3
2
1
上面的语法知识点有很多,比如高级数学表达式(())
,不过你只要知道,while 的整个框架就足够了。
不过更为常用的是第二种形式,结合read 语句,read 命令被用来从标准输入读取单行数据,比如我们可以用管道符,读取的内容传递给read:
❯ cat test.txt | while read id; do echo ${id}_loop ;done
1_loop
2_loop
3_loop
4_loop
5_loop
6_loop
7_loop
8_loop
9_loop
10_loop
和其他编程语言一样,shell 也提供了循环控制的方法,break 和continue。
break 可以直接跳出循环:
❯ a=10
❯ while;do echo $a;a=$(( --a )); if (( a<5 )); then break;fi;done
10
9
8
7
6
5
❯ echo $a
4
当我们使用嵌套循环时,还可以跳出指定的循环层数break n
。ps:我实在厌恶写shell 的循环。不想写了。
continue 则是跳出当前的循环。
我们同样可以将循环语法认为是一个主体,所以我们可以对其输出进行重定向或使用管道符号:
❯ cat test.txt
1
2
3
4
5
6
7
8
9
10
❯ cat test.txt| while read id;do echo $id; done | sort -nr
10
9
8
7
6
5
4
3
2
1
until 和while 真好相反,while 是满足条件,即命令的状态码不为0 才退出,而until 则是返回的状态码为0 才退出,即条件表达式被满足。其实和语义也非常相符,until
正是知道……才
。
❯ until (( a <= 3 ));do a=$(( --a )); echo $a; done
9
8
7
6
5
4
3
当使用循环遍历文本文件时,有时候遇到下面情况。如果我们想要遍历每行。却因为空格,拆分了本来一行中的内容。
cat ifs_test.txt
a b
c
d
$ for i in $(cat ifs_test.txt)
> do
> echo $i
> done
a
b
c
d
这是因为shell中存在特殊的环境变量 IFS
,叫做内部字符分隔符
。默认下shell 的分隔符包括:空格、制表符、换行符。
因此如果想要解决上面的问题,就需要修改IFS。IFS=$'\n'
,使shell 只能识别到换行符作为分割点。
其实while 和for 完全是足够了的。
for i in
和C 语言风格的for 会很好用;事情当然是越简单越好。
此外,shell并不会考虑你的感受的,所以全部的缩进,建议你在如sublime 等编辑器下操作:
或者是感受shell 满满的恶意吧:
当然你如果训练有素,直接靠分号操作,也不是不行:
cat test.txt| while read id;do echo $id; done | sort -nr
[1]
Shell 流程控制 | 菜鸟教程: https://www.runoob.com/linux/linux-shell-process-control.html
[2]
shell编程:for循环 - trafalgar999 - 博客园: https://www.cnblogs.com/trafalgar999/p/13121405.html#:~:text=C%20%E8%AF%AD%E8%A8%80%E7%9A%84%20for%20%E5%91%BD%E4%BB%A4%20bash%20shell%20%E4%B9%9F%E6%94%AF%E6%8C%81%E4%B8%80%E7%A7%8D%20for,for%20%28%28variable%20assignment%20%3B%20condition%20%3B%20iteration%20process%29%29