上回我们研究和探讨了Linux shell编程中for 循环语句,与在C/C++中一样,for 循环语句Linux shell编程中有很多灵活的用法。今天我们来研究和探讨while循环语句。
我们继续以for循环语句中的例子,计算 从1到10与2的乘积 并输出。
# csdn @ edu in ~ [20:35:57]
$ i=1; while (( $i <= 10 )) ; do echo "$i * 2 = $(expr $i \* 2)"; i=$(expr $i + 1); done
1 * 2 = 2
2 * 2 = 4
3 * 2 = 6
4 * 2 = 8
5 * 2 = 10
6 * 2 = 12
7 * 2 = 14
8 * 2 = 16
9 * 2 = 18
10 * 2 = 20# csdn @ edu in ~ [20:36:21]
$
[csdn ~]$ i=1; while (( $i <= 10 )) ; do echo "$i * 2 = $(expr $i \* 2)"; i=$(expr $i + 1); done
1 * 2 = 2
2 * 2 = 4
3 * 2 = 6
4 * 2 = 8
5 * 2 = 10
6 * 2 = 12
7 * 2 = 14
8 * 2 = 16
9 * 2 = 18
10 * 2 = 20
表达式 $(expr $i \* 2) 中 \* 前后要用空格与操作数分隔,表达式 i=$(expr $i + 1) 中 + 前后要用空格与操作数分隔,否则结果就会出错。
对于经常使用i++、i--运算符的程序员来说,使用i=i+1多多少少有些别扭。
由于i++或++i是表达式而不是命令,所以我们在使用这种表达式时要变通一下。
# csdn @ edu in ~ [21:08:50]
$ i=1; while (( $i <= 10 )) ; do echo "$i * 2 = $(expr $i \* 2)"; let i++; done
1 * 2 = 2
2 * 2 = 4
3 * 2 = 6
4 * 2 = 8
5 * 2 = 10
6 * 2 = 12
7 * 2 = 14
8 * 2 = 16
9 * 2 = 18
10 * 2 = 20# csdn @ edu in ~ [21:09:03]
$
[csdn ~]$ i=1; while (( $i <= 10 )) ; do echo "$i * 2 = $(expr $i \* 2)"; let i++; done
1 * 2 = 2
2 * 2 = 4
3 * 2 = 6
4 * 2 = 8
5 * 2 = 10
6 * 2 = 12
7 * 2 = 14
8 * 2 = 16
9 * 2 = 18
10 * 2 = 20
[csdn ~]$
# csdn @ edu in ~ [21:21:29]
$ i=1; while (( i++ <= 10 )) ; do echo "$i * 2 = $(expr $i \* 2)"; done
2 * 2 = 4
3 * 2 = 6
4 * 2 = 8
5 * 2 = 10
6 * 2 = 12
7 * 2 = 14
8 * 2 = 16
9 * 2 = 18
10 * 2 = 20
11 * 2 = 22# csdn @ edu in ~ [21:21:40]
$
[csdn ~]$ i=1; while (( i++ <= 10 )) ; do echo "$i * 2 = $(expr $i \* 2)"; done
2 * 2 = 4
3 * 2 = 6
4 * 2 = 8
5 * 2 = 10
6 * 2 = 12
7 * 2 = 14
8 * 2 = 16
9 * 2 = 18
10 * 2 = 20
11 * 2 = 22
[csdn ~]$
# csdn @ edu in ~ [21:31:12]
$ i=0; while (( i++ && i <= 10 )) ; do echo "$i * 2 = $(expr $i \* 2)"; done# csdn @ edu in ~ [21:38:46]
$ i=0; while (( ++i && i <= 10 )) ; do echo "$i * 2 = $(expr $i \* 2)"; done
1 * 2 = 2
2 * 2 = 4
3 * 2 = 6
4 * 2 = 8
5 * 2 = 10
6 * 2 = 12
7 * 2 = 14
8 * 2 = 16
9 * 2 = 18
10 * 2 = 20# csdn @ edu in ~ [21:39:10]
$
[csdn ~]$ i=0; while (( i++ && i <= 10 )) ; do echo "$i * 2 = $(expr $i \* 2)"; done
[csdn ~]$ i=0; while (( ++i && i <= 10 )) ; do echo "$i * 2 = $(expr $i \* 2)"; done
1 * 2 = 2
2 * 2 = 4
3 * 2 = 6
4 * 2 = 8
5 * 2 = 10
6 * 2 = 12
7 * 2 = 14
8 * 2 = 16
9 * 2 = 18
10 * 2 = 20
[csdn ~]$
在上面的实例中,使用 i++ && i <= 10 作为循环条件表达式时,没有输出结果。
使用 ++i && i <= 10 作为循环条件表达式才能正确输出结果。
我们先定义一个数组s=(b d 3 0),并以0作为最后一个数组元素,然后定义循环变量i并初始化,接着使用while循环逐一访问数组s的成员值并输出,如果成员值 是小写字母,就是输出提示is a lowercase letter,否则输出提示is not a letter,直到遇到最后一个数组元素0,循环结束。
命令行为:
s=(b d 3 0); i=1; while [[ ${s[i]} != '0' ]] ; do if [[ ${s[i]} > 'a' && ${s[i]} < 'z' ]]; then echo ${s[i]} is a lowercase letter; else echo ${s[i]} is not a letter; fi; let i++; done
由于CSDN程序员研修院提供的linux环境不能让以上命令完整显示,所以我们分几行输入:
# csdn @ edu in ~ [12:23:33]
$ s=(b d 3 0); i=1; while [[ ${s[i]} != '0' ]] ;
while> do if [[ ${s[i]} > 'a' && ${s[i]} < 'z' ]]; then echo ${s[i]} is a lowercase letter; else echo ${s[i]} is not a letter; fi;
while> let i++;
while> done
b is a lowercase letter
d is a lowercase letter
3 is not a letter# csdn @ edu in ~ [12:24:31]
$
注意:在zsh中,数组下标是从1开始的。所以上例中数组下标变量i的初始值为1。
s=(b d 3 0); i=0; while [[ ${s[i]} != '0' ]] ; do if [[ ${s[i]} > 'a' && ${s[i]} < 'z' ]]; then echo ${s[i]} is a lowercase letter; else echo ${s[i]} is not a letter; fi; let i++; done
user @ host : ~ $ s=(b d 3 0); i=0; while [[ ${s[i]} != '0' ]] ; do if [[ ${s[i]} > 'a' && ${s[i]} < 'z' ]]; then echo ${s[i]} is a lowercase letter; else echo ${s[i]} is not a letter; fi; let i++; done
b is a lowercase letter
d is a lowercase letter
3 is not a letter
user @ host : ~ $ ^C
注意:在bash中,数组下标是从0开始的。所以上例中数组下标变量i的初始值为0。
定义字符串s=abcd0,初始化循环变量i,然后从i开始截取字符串s值并输出,直到截取的字符串为0时结束循环。
[csdn ~]$ s=abcd0; i=0; while [[ ${s:i} != '0' ]] ; do echo ${s:i}; let i++; done
abcd0
bcd0
cd0
d0
[csdn ~]$
(1)在zsh命令行执行不成功
# csdn @ edu in ~ [13:03:22]
$ s=abcd0; i=1; while [[ ${s:i} != '0' ]] ; do echo ${s:i}; let i++; done
zsh: unrecognized modifier `i'# csdn @ edu in ~ [13:03:26] C:1
$ s=abcd0; i=1; while [[ ${s:$i} != '0' ]] ; do echo ${s:i}; let i++; done
zsh: unrecognized modifier `i'# csdn @ edu in ~ [13:03:32] C:1
$ s=abcd0; i=1; while [[ ${ s:${i} } != '0' ]] ; do echo ${s:i}; let i++; done
zsh: bad substitution# csdn @ edu in ~ [13:03:54] C:1
$ s=abcd0; i=1; while [[ ${s:${i}} != '0' ]] ; do echo ${s:i}; let i++; done
zsh: unrecognized modifier `i'# csdn @ edu in ~ [13:04:01] C:1
$ s=abcd0; i=1; while (( ${s:${i}} != '0' )) ; do echo ${s:i}; let i++; done
zsh: bad math expression: operand expected at `'0' '# csdn @ edu in ~ [13:04:11]
$ s=abcd0; i=1; while (( ${s:i} != '0' )) ; do echo ${s:i}; let i++; done
zsh: unrecognized modifier `i'# csdn @ edu in ~ [13:04:22]
$ s=abcd0; i=1; while (( ${s:$i} != '0' )) ; do echo ${s:i}; let i++; done
zsh: bad math expression: operand expected at `'0' '# csdn @ edu in ~ [13:04:30]
$
# csdn @ edu in ~ [14:50:09] C:126
$ echo '#!/bin/zsh' > a.sh# csdn @ edu in ~ [14:50:51]
$ echo i=1 >> a.sh# csdn @ edu in ~ [14:50:51]
$ echo 'while [[ ${s:i} != '0' ]]' >> a.sh# csdn @ edu in ~ [14:50:51]
$ echo do >> a.sh# csdn @ edu in ~ [14:50:51]
$ echo 'echo ${#s:i}' >> a.sh# csdn @ edu in ~ [14:50:51]
$ echo 'let i++;' >> a.sh# csdn @ edu in ~ [14:50:51]
$ echo done >> a.sh# csdn @ edu in ~ [14:50:53]
$ cat a.sh
#!/bin/zsh
i=1
while [[ ${s:i} != 0 ]]
do
echo ${#s:i}
let i++;
done# csdn @ edu in ~ [14:50:57]
$ . ./a.sh
./a.sh:3: unrecognized modifier `i'
我们利用echo 配合输出重定向创建了脚本文件a.sh,但脚本文件a.sh也没运行成功。
我们用无限循环每隔30秒显示提示信息 press Ctrl+C to exit,在用户按下Ctrl+C后结束循环。
# csdn @ edu in ~ [15:06:21]
$ while true; do echo 'press Ctrl+C to exit'; sleep 30s; done
press Ctrl+C to exit
press Ctrl+C to exit
press Ctrl+C to exit
press Ctrl+C to exit
^C%# csdn @ edu in ~ [15:08:23] C:130
$
[csdn ~]$ while true; do echo 'press Ctrl+C to exit'; sleep 30s; done
press Ctrl+C to exit
press Ctrl+C to exit
^C
[csdn ~]$
在上面的例子中,为了避免提示信息 press Ctrl+C to exit 刷屏,我们使用了命令:
sleep 30s
来等待30秒钟。
在Linux中,冒号(:) 有很多种用法,其中之一是作为空表达式或空命令,返回值为0。
我们可以创建一个包含以下两条命令的脚本文件a.sh 来观察冒号(:)作为空命令执行时的返回值(保存在$?中)。
:
echo $?
脚本文件创建和执行情况:
# csdn @ edu in ~ [15:22:38]
$ echo ':' > a.sh# csdn @ edu in ~ [15:23:20]
$ echo 'echo $?'>> a.sh# csdn @ edu in ~ [15:23:27]
$ cat a.sh
:
echo $?# csdn @ edu in ~ [15:23:33]
$ . ./a.sh
0# csdn @ edu in ~ [15:23:36]
$
# csdn @ edu in ~ [15:08:23] C:130
$ while : ; do echo 'press Ctrl+C to exit'; sleep 30s; done
press Ctrl+C to exit
press Ctrl+C to exit
press Ctrl+C to exit
^C%# csdn @ edu in ~ [15:12:29] C:130
# csdn @ edu in ~ [15:13:11] C:130
$ exec bash
[csdn ~]$ while : ; do echo 'press Ctrl+C to exit'; sleep 30s; done
press Ctrl+C to exit
press Ctrl+C to exit
^C
[csdn ~]$
一般推荐使用冒号(:) 作为循环表达式的无限循环,因为使用冒号(:)命令系统资源开销更小。