bash$echo"$IFS"(当 $IFS 设置为缺省值时,显示空行。)bash$echo"$IFS"|cat-vte^I$$(显示空白符:首先是一个空格,然后是^I [水平制表符],然后是换行符,最后在末尾显示"$"。)bash$bash-c'set w x y z; IFS=":-;"; echo "$*"'w:x:y:z(从字符串中解析命令,然后将命令参数分配给位置参数。)
通过设置 $IFS 来忽略文件路径名中空格带来的影响。
IFS="$(printf '\n\t')"# 按 David Wheeler 所述。
相比于其他字符,变量 $IFS 在处理空白符时有所不同。
样例 9-1. $IFS 与空白符
#!/bin/bash# ifs.shvar1="a+b+c"var2="d-e-f"var3="g,h,i"IFS=+# 加号会被解析成分隔符。echo $var1 # a b cecho $var2 # d-e-fecho $var3 # g,h,iechoIFS="-"# 恢复对加号的默认解析。# 现在减号会被解析成分隔符。echo $var1 # a+b+cecho $var2 # d e fecho $var3 # g,h,iechoIFS=","# 现在逗号会被解析成分隔符。# 恢复对减号的默认解析。echo $var1 # a+b+cecho $var2 # d-e-fecho $var3 # g h iechoIFS=" "# 现在空格会被解析成分隔符。# 逗号恢复成默认解析。echo $var1 # a+b+cecho $var2 # d-e-fecho $var3 # g,h,i# ======================================================== ## 然而...# $IFS 处理空白符的方式不同其他字符。output_args_one_per_line(){for argdoecho"[$arg]"done# ^ ^ 为了获得更好的视觉体验,把参数放到了括号里。}echo; echo"IFS=\" \""echo"-------"IFS=" "var=" a b c "# ^ ^^ ^^^output_args_one_per_line $var # output_args_one_per_line `echo " a b c "`# [a]# [b]# [c]echo; echo"IFS=:"echo"-----"IFS=:var=":a::b:c:::"# 与上面一样的模式,# ^ ^^ ^^^ #+ 仅仅是将 " " 替换成了 ":" ...output_args_one_per_line $var# []# [a]# []# [b]# [c]# []# []# 注意那些“空的”括号。# 同样的情况也会出现在 awk 命令所使用的 "FS" 字段分隔符中。echoexit
#!/bin/bash# reply.sh# REPLY 是 'read' 命令的默认接收参数。echoecho-n"What is your favorite vegetable? "readecho"Your favorite vegetable is $REPLY."# 当且仅当 'read' 命令没有接收参数的时候,#+ REPLY 才能保存最近一次 'read' 命令接收的值。echoecho-n"What is your favorite fruit? "readfruitecho"Your favorite fruit is $fruit."echo"but..."echo"Value of \$REPLY is still $REPLY."# 因为变量 $fruit 接收了新一次 "read" 命令所读入的值,#+ 所以 $REPLY 仍旧存储的是上一次接收的值。echoexit0
$SECONDS
该变量记录到目前为止脚本执行的时间,单位为秒。
#!/bin/bashTIME_LIMIT=10INTERVAL=1echoecho"Hit Control-C to exit before $TIME_LIMIT seconds."echowhile [ "$SECONDS"-le"$TIME_LIMIT" ]do# $SECONDS 是一个 shell 的内部变量。if [ "$SECONDS"-eq1 ]then units=secondelse units=secondsfiecho"This script has been running $SECONDS $units."# 在一台性能较差或负载过重的设备上,#+ 这个脚本可能会偶尔跳过几个计数。sleep $INTERVALdoneecho-e"\a"# 发出蜂鸣声!exit0
# 只能在 Bash 2.05b 及之后的版本中成功执行。TMOUT=3# 提示会在 3 秒后超时。echo"What is your favorite song?"echo"Quickly now, you only have $TMOUT seconds to answer!"readsongif [ -z"$song" ]then song="(no answer)"# 默认值。fiecho"Your favorite song is $song."
该 ID 表示的是当前用户的真实 ID,即使用户通过 su 命令临时切换至另一个用户,这个 ID 也不会改变。$UID 是一个只读变量,不能够被命令行或是脚本中的命令所修改,并与内建命令 id 相对应。
样例 9-5. 我是 root 用户吗?
#!/bin/bash# am-i-root.sh: 我是否是 root 用户?ROOT_UID=0# Root 用户的 $UID 为 0。if [ "$UID"-eq"$ROOT_UID" ] # 只有真正的 "root" 用户才能经受得住考研。thenecho"You are root."elseecho"You are just an ordinary user (but mom loves you just the same)."fiexit0# ============================================================= ## 下面的代码将不会被执行,因为脚本已经退出了。# 另外一种判断是否是 root 用户的方法:ROOTUSER_NAME=rootusername=`id-nu`# 或是... username=`whoami`if [ "$username"="$ROOTUSER_NAME" ]thenecho"Rooty, toot, toot. You are root."elseecho"You are just a regular fella."fi
#!/bin/bash# arglist.sh# 在调用该脚本时需要跟上一些参数,例如 "one two three" ...E_BADARGS=85if [ !-n"$1" ]thenecho"Usage: `basename $0` argument1 argument2 etc."exit $E_BADARGSfiechoindex=1# 初始化计数器。echo"Listing args with \"\$*\":"for arg in"$*"# 如果这里没有引用 "$*",脚本将不会正常运行。doecho"Arg #$index = $arg"let"index+=1"done# $* 将所有参数视作一个单词。echo"Entire arg list seen as single word."echoindex=1# 重置计数器。# 如果忘了这一步将会发生什么?echo"Listing args with \"\$@\":"for arg in"$@"doecho"Arg #$index = $arg"let"index+=1"done# $@ 将所有参数视作独立的单词。echo"Arg list seen as separate words."echoindex=1# 重置计数器。echo"Listing args with \$* (unquoted):"for arg in $*doecho"Arg #$index = $arg"let"index+=1"done# 未被引用的 $* 将所有参数视作独立的单词。echo"Arg list seen as separate words."exit0
#!/bin/bash# Bash 的内部变量 "$*" 和 "$@" 拥有不稳定的行为,#+ 这些行为是否出现通常依赖于它们是否是被引用的状态。# 下面的代码会演示在分词和换行时,这些变量所会出现的一些不一致的处理方式。set--"First one""second""third:one""""Fifth: :one"# 设置脚本参数,$1, $2, $3 等等。echoecho'IFS unchanged, using "$*"'c=0for i in"$*"# 被引用状态。doecho"$((c+=1)): [$i]"# 这一行在下面所有的例子中都保持不变。# 输出参数。doneecho---echo'IFS unchanged, using $*'c=0for i in $* # 未被引用状态。doecho"$((c+=1)): [$i]"doneecho---echo'IFS unchanged, using "$@"'c=0for i in"$@"doecho"$((c+=1)): [$i]"doneecho---echo'IFS unchanged, using $@'c=0for i in $@doecho"$((c+=1)): [$i]"doneecho---IFS=:echo'IFS=":", using "$*"'c=0for i in"$*"doecho"$((c+=1)): [$i]"doneecho---echo'IFS=":", using $*'c=0for i in $*doecho"$((c+=1)): [$i]"doneecho---var=$*echo'IFS=":", using "$var" (var=$*)'c=0for i in"$var"doecho"$((c+=1)): [$i]"doneecho---echo'IFS=":", using $var (var=$*)'c=0for i in $vardoecho"$((c+=1)): [$i]"doneecho---var="$*"echo'IFS=":", using $var (var="$*")'c=0for i in $vardoecho"$((c+=1)): [$i]"doneecho---echo'IFS=":", using "$var" (var="$*")'c=0for i in"$var"doecho"$((c+=1)): [$i]"doneecho---echo'IFS=":", using "$@"'c=0for i in"$@"doecho"$((c+=1)): [$i]"doneecho---echo'IFS=":", using $@'c=0for i in $@doecho"$((c+=1)): [$i]"doneecho---var=$@echo'IFS=":", using $var (var=$@)'c=0for i in $vardoecho"$((c+=1)): [$i]"doneecho---echo'IFS=":", using "$var" (var=$@)'c=0for i in"$var"doecho"$((c+=1)): [$i]"doneecho---var="$@"echo'IFS=":", using "$var" (var="$@")'c=0for i in"$var"doecho"$((c+=1)): [$i]"doneecho---echo'IFS=":", using $var (var="$@")'c=0for i in $vardoecho"$((c+=1)): [$i]"doneecho# 尝试在 ksh 或是 zsh -y 下执行这个脚本。exit0# 这个样例是由 Stephane Chazelas 所编写,#+ 由本书作者轻微改动。
类似于 递归。在本文中,嵌套是指代一种模式被嵌入在一种更大的模式中。在 1913 年出版的韦伯斯特大辞典中用一种更加优雅的方式解释了什么是嵌套:“一组按体积大小排列的盒子、箱子或是类似的东西,它们中的每一个都被放入到另一个更大的箱子中。(A collection of boxes, cases, or the like, of graduated size, each put within the one next larger.)”。