例子10-1 一个简单的例子:
#!/bin/bash
# 列出所有的行星名称.
for planet in Mercury Venus Earth Mars Jupiter Saturn Uranus Neptune Pluto
do
echo $planet # 每个行星被单独打印在一行上.
done
echo
for planet in "Mercury Venus Earth Mars Jupiter Saturn Uranus Neptune Pluto"
# 所有的行星名称打印在同一行上.
# 整个'list'只有一个变量,用""封成一个变量.
do
echo $planet
done
exit 0
输出如下:
[root@dba 10]# sh 10_1.sh
Mercury
Venus
Earth
Mars
Jupiter
Saturn
Uranus
Neptune
Pluto
Mercury Venus Earth Mars Jupiter Saturn Uranus Neptune Pluto
10-2 每个[list]元素带两个参数的for循环
#!/bin/bash
# 再访行星.
# 分配行星的名字和它距太阳的距离.
for planet in "Mercury 36" "Venus 67" "Earth 93" "Mars 142" "Jupiter 483"
do
set -- $planet # Parses variable "planet" and sets positional parameters.
# "--" 将防止$planet为空,或者是以一个破折号开头.
# 可能需要保存原始的位置参数,因为它们被覆盖了.
# 一种方法就是使用数组,
# original_params=("$@")
echo "$1 $2,000,000 miles from the sun"
#-------two tabs---把后边的0和$2连接起来
done
# (Thanks, S.C., for additional clarification.)
exit 0
运行结果:
[root@dba 10]# sh 10_2.sh
Mercury 36,000,000 miles from the sun
Venus 67,000,000 miles from the sun
Earth 93,000,000 miles from the sun
Mars 142,000,000 miles from the sun
Jupiter 483,000,000 miles from the sun
10-3 文件信息: 对包含在变量中的文件列表进行操作
[root@dba 10]# cat 10_3.sh
#!/bin/bash
# fileinfo.sh
FILES="/usr/sbin/accept
/usr/sbin/pwck
/usr/sbin/chroot
/usr/bin/fakefile
/sbin/badblocks
/sbin/ypbind" # 你关心的文件列表.
# 扔进去一个假文件, /usr/bin/fakefile.
echo
for file in $FILES
do
if [ ! -e "$file" ] # 检查文件是否存在.
then
echo "$file does not exist."; echo
continue # 继续下一个.
fi
ls -l $file | awk '{ print $9 " file size: " $5 }' # 打印2个域.
whatis `basename $file` # 文件信息.
# 注意whatis数据库需要提前建立好.
# 要想达到这个目的, 以root身份运行/usr/bin/makewhatis.
echo
done
exit 0
运行结果:
[root@dba 10]# sh 10_3.sh
/usr/sbin/accept file size: 10
accept (2) - accept a connection on a socket
accept (3p) - accept a new connection on a socket
/usr/sbin/pwck file size: 42416
pwck (8) - verify integrity of password files
/usr/sbin/chroot file size: 31776
chroot (1) - run command or interactive shell with special root directory
chroot (2) - change root directory
/usr/bin/fakefile does not exist.
/sbin/badblocks file size: 29752
badblocks (8) - search a device for bad blocks
/sbin/ypbind does not exist.
10-4 在for循环中操作文件
#!/bin/bash
# list-glob.sh: 在for循环中使用文件名扩展产生 [list]
echo
for file in *
# ^ 在表达式中识别文件扩展符时,
#+ Bash 将执行文件名扩展.
do
ls -l "$file" # Lists all files in $PWD (current directory).
# 回想一下,通配符"*"能够匹配所有文件,
#+ 然而,在"文件扩展符"中,是不能匹配"."文件的.
# 如果没匹配到任何文件,那它将扩展成自己
# 为了不让这种情况发生,那就设置nullglob选项
#+ (shopt -s nullglob).
# Thanks, S.C.
done
echo; echo
for file in [jx]*
do
rm -f $file # 只删除当前目录下以"j"或"x"开头的文件.
echo "Removed file \"$file\"".
done
echo
exit 0
运行结果:
[root@dba 10]# sh 10_4.sh
-rw-r--r--. 1 root root 407 7月 8 13:25 10_1.sh
-rw-r--r--. 1 root root 601 7月 8 13:29 10_2.sh
-rw-r--r--. 1 root root 677 7月 8 13:42 10_3.sh
-rw-r--r--. 1 root root 724 7月 8 14:04 10_4.sh
例子10-6 使用命令替换来产生for循环的[list]
#!/bin/bash
# for-loopcmd.sh: 带[list]的for循环
#+ [list]是由命令替换产生的.
NUMBERS="9 7 3 8 37.53"
for number in `echo $NUMBERS` # for number in 9 7 3 8 37.53
do
echo -n "$number "
done
echo
exit 0
运行结果:
[root@dba 10]# sh 10_6.sh
9 7 3 8 37.53
例子10-7 对于二进制文件的grep替换
#!/bin/bash
# bin-grep.sh: 在一个二进制文件中定位匹配字串.
# 对于二进制文件的一个grep替换
# 与"grep -a"的效果相似
E_BADARGS=65
E_NOFILE=66
if [ $# -ne 2 ]
then
echo "Usage: `basename $0` search_string filename"
exit $E_BADARGS
fi
if [ ! -f "$2" ]
then
echo "File \"$2\" does not exist."
exit $E_NOFILE
fi
IFS="\n" # 由Paulo Marcel Coelho Aragao提出的建议.
for word in $( strings "$2" | grep "$1" )
# "strings" 命令列出二进制文件中的所有字符串.
# 输出到管道交给"grep",然后由grep命令来过滤字符串.
do
echo $word
done
# S.C. 指出, 行23 - 29 可以被下边的这行来代替,
# strings "$2" | grep "$1" | tr -s "$IFS" '[\n*]'
# 试试用"./bin-grep.sh mem /bin/ls"来运行这个脚本.
exit 0
测试结果:
[root@dba 10]# sh 10_7.sh mem /bin/ls
memory exhausted
__mempcpy_chk
memset
mempcpy
memcpy
__memcpy_chk
sigismember
memmove
例子 10-8 列出系统上的所有用户:
#!/bin/bash
# userlist.sh
PASSWORD_FILE=/etc/passwd
n=1 # User number
for name in $(awk 'BEGIN{FS=":"}{print $1}' < "$PASSWORD_FILE" )
# 域分隔 = : ^^^^^^
# 打印出第一个域 ^^^^^^^^
# 从password文件中取得输入 ^^^^^^^^^^^^^^^^^
do
echo "USER #$n = $name"
let "n += 1"
done
# USER #1 = root
# USER #2 = bin
# USER #3 = daemon
# ...
# USER #30 = bozo
exit 0
# 练习:
# --------
# 一个普通用户(或者是一个普通用户运行的脚本)
#+ 怎么能读取/etc/password呢?
# 这是否是一个安全漏洞? 为什么是?为什么不是?
实验结果:
[root@dba 10]# sh 10_8.sh
USER #1 = root
USER #2 = bin
USER #3 = daemon
USER #4 = adm
USER #5 = lp
USER #6 = sync
USER #7 = shutdown
USER #8 = halt
USER #9 = mail
USER #10 = uucp
USER #11 = operator
USER #12 = games
USER #13 = gopher
USER #14 = ftp
USER #15 = nobody
USER #16 = dbus
USER #17 = usbmuxd
USER #18 = vcsa
USER #19 = rpc
USER #20 = rtkit
USER #21 = avahi-autoipd
USER #22 = abrt
USER #23 = rpcuser
USER #24 = nfsnobody
USER #25 = haldaemon
USER #26 = gdm
USER #27 = ntp
USER #28 = apache
USER #29 = saslauth
USER #30 = postfix
USER #31 = pulse
USER #32 = sshd
USER #33 = tcpdump
USER #34 = fei
例子 10-19 嵌套循环
#!/bin/bash
# nested-loop.sh: 嵌套的"for" 循环.
outer=1 # 设置外部循环计数.
# 开始外部循环.
for a in 1 2 3 4 5
do
echo "Pass $outer in outer loop."
echo "---------------------"
inner=1 # 重设内部循环的计数.
# ===============================================
# 开始内部循环.
for b in 1 2 3 4 5
do
echo "Pass $inner in inner loop."
let "inner+=1" # 增加内部循环计数.
done
# 内部循环结束.
# ===============================================
let "outer+=1" # 增加外部循环的计数.
echo # 每次外部循环之间的间隔.
done
# 外部循环结束.
exit 0
测试结果:
[root@dba 10]# sh 10_19.sh
Pass 1 in outer loop.
---------------------
Pass 1 in inner loop.
Pass 2 in inner loop.
Pass 3 in inner loop.
Pass 4 in inner loop.
Pass 5 in inner loop.
Pass 2 in outer loop.
---------------------
Pass 1 in inner loop.
Pass 2 in inner loop.
Pass 3 in inner loop.
Pass 4 in inner loop.
Pass 5 in inner loop.
Pass 3 in outer loop.
---------------------
Pass 1 in inner loop.
Pass 2 in inner loop.
Pass 3 in inner loop.
Pass 4 in inner loop.
Pass 5 in inner loop.
Pass 4 in outer loop.
---------------------
Pass 1 in inner loop.
Pass 2 in inner loop.
Pass 3 in inner loop.
Pass 4 in inner loop.
Pass 5 in inner loop.
Pass 5 in outer loop.
---------------------
Pass 1 in inner loop.
Pass 2 in inner loop.
Pass 3 in inner loop.
Pass 4 in inner loop.
Pass 5 in inner loop.
例子 10-20 . break和continue命令在循环中的效果:
#!/bin/bash
LIMIT=19 # 上限
echo
echo "Printing Numbers 1 through 20 (but not 3 and 11)."
a=0
while [ $a -le "$LIMIT" ]
do
a=$(($a+1))
if [ "$a" -eq 3 ] || [ "$a" -eq 11 ] # Excludes 3 and 11.
then
continue # 跳过本次循环剩下的语句.
fi
echo -n "$a " # 在$a等于3和11的时候,这句将不会执行.
done
# 练习:
# 为什么循环会打印到20?
echo; echo
echo Printing Numbers 1 through 20, but something happens after 2.
##################################################################
# 同样的循环, 但是用'break'来代替'continue'.
a=0
while [ "$a" -le "$LIMIT" ]
do
a=$(($a+1))
if [ "$a" -gt 2 ]
then
break # Skip entire rest of loop.
fi
echo -n "$a "
done
echo; echo; echo
exit 0
运行结果:
[root@dba 10]# sh 10_20.sh
Printing Numbers 1 through 20 (but not 3 and 11).
1 2 4 5 6 7 8 9 10 12 13 14 15 16 17 18 19 20
Printing Numbers 1 through 20, but something happens after 2.
1 2
例子10-21 多层循环的退出
#!/bin/bash
# break-levels.sh: 退出循环.
# "break N" 退出N层循环.
for outerloop in 1 2 3 4 5
do
echo -n "Group $outerloop: "
# --------------------------------------------------------
for innerloop in 1 2 3 4 5
do
echo -n "$innerloop "
if [ "$innerloop" -eq 3 ]
then
break 2 # 试试 break 2 来看看发生什么.
# (里面一层循环和外面一层循环都被退出了..)
fi
done
# --------------------------------------------------------
echo
done
echo
exit 0
运行结果:break不带参数
[root@dba 10]# sh 10_21.sh
Group 1: 1 2 3
Group 2: 1 2 3
Group 3: 1 2 3
Group 4: 1 2 3
Group 5: 1 2 3
break 2;
[root@dba 10]# sh 10_21.sh
Group 1: 1 2 3
例子 10-22 .多层循环的continue
#!/bin/bash
# "continue N" 命令, 将让N层的循环全部被continue.
for outer in I II III IV V # 外部循环
do
echo; echo -n "Group $outer: "
# --------------------------------------------------------------------
for inner in 1 2 3 4 5 6 7 8 9 10 # 内部循环
do
if [ "$inner" -eq 7 ]
then
continue 2 # continue 2层, 也就是到outer循环上.
# 将"continue 2"替换为一个单独的"continue"
# 来看一下一个正常循环的行为.
fi
echo -n "$inner " # 7 8 9 10 将不会被echo
done
# --------------------------------------------------------------------
#译者注:如果在此处添加echo的话,当然也不会输出.
done
echo; echo
# 练习:
# 准备一个有意义的"continue N"的使用,放在脚本中.
exit 0
sh 10_22.sh
Group I: 1 2 3 4 5 6
Group II: 1 2 3 4 5 6
Group III: 1 2 3 4 5 6
Group IV: 1 2 3 4 5 6
Group V: 1 2 3 4 5 6
contine 为1时:
Group I: 1 2 3 4 5 6 8 9 10
Group II: 1 2 3 4 5 6 8 9 10
Group III: 1 2 3 4 5 6 8 9 10
Group IV: 1 2 3 4 5 6 8 9 10
Group V: 1 2 3 4 5 6 8 9 10
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/29313086/viewspace-1726544/ ,如需转载,请注明出处,否则将追究法律责任。