继续开始shell十三问中11-13问和后续补充的笔记,加油!
(14)输入重定向与输出重定向
- “>”是标准输出重定向,可以把输出结果送入文件
- “<”是标准输入重定向,可以重新指定文件的内容作为输入
- “2>”是标准错误重定向,可以把命名执行出现的错误提示送入文件
如果你想把标准输出和标准错误输出到一个文件中,可以使用如下的方法
- $ ls my.file no.such.file 1>file.both 2>&1 (错误到输出)
- $ ls my.file no.such.file 2>file.both >&2(输出到错误)
使用“<<”追加写入,“<”为最后一次写入的内容
(15)锁定文件避免覆盖写入
$ set -o noclobber $ echo "4" > file.out -bash: file: cannot overwrite existing file
如上所示即可避免覆盖写入,当想再次使用后
$ set +o noclobber $ echo "5" > file.out $ cat file.out 5
如果想临时的覆盖文档内容,而不取消限制,那么可以使用”>|”
$ set -o noclobber $ echo "6" >| file.out $ cat file.out 6
来看一道题,为什么file文件为空
$ echo "some text here" > file $ cat < file some text here $ cat < file > file.bak $ cat < file.bak some text here $ cat < file > file $ cat < file
[toggle title="点击展开"]
前面提到:$ cat < file > file 之后原本有内容的档案结果却被洗掉了﹗
要理解这一现像其实不难,这只是 priority 的问题而已:
* 在 IO Redirection 中,stdout 与 stderr 的管道会先准备好,才会从 stdin 读进资料。
也就是说,在上例中,> file 会先将 file 清空,然后才读进 < file ,
但这时候档案已经被清空了,因此就变成读不进任何资料了…
[/toggle]
2个问题
$ cat <> file (如果说前面的用优先级解释,但是这个不理解,暂时放一放吧) $ cat < file >> file
(16)管道内保存数据
在 cm1 | cm2 | cm3 … 这段 pipe line 中,若要将 cm2 的结果存到某一档案呢?
若你写成 cm1 | cm2 > file | cm3 的话,
那你肯定会发现 cm3 的 stdin 是空的﹗(当然啦,你都将水管接到别的水池了﹗)
聪明的你或许会如此解决:
cm1 | cm2 > file ; cm3 < file
虽然这样可行,但是文件I/O会加倍,严重影响效率,所以解决方法是使用tee命令,如下:
cm1 | cm2 | tee file | cm3
(17)几个条件判断
[toggle title="&&与||实现"]
comd1 && { comd2 comd3 : } || { comd4 comd5 }
[/toggle]
[toggle title="if...than...else句式"]
if comd1 then comd2 comd3 else comd4 comd5 fi
if comd1; then comd2 elif comd3; then comd4 else comd5 fi
[/toggle]
这个的意思是:意思是说:
若 comd1 为 true ,然则执行 comd2 ﹔否则再测试 comd3 ,然则执行 comd4 ﹔倘若 comd1 与 comd3 均不成立,那就执行 comd5 。
提别一提的是,当than后面不需要接命令的话,可以使用“:”符号占位,这里就不多记录了,和C语言一样,多多的书写实践还能写出得心应手的脚本。
(18)循环
原文写的很简单易懂,我就直接摘过来了~
最后要介绍的是 shell script 设计中常见的”循环”(loop)。
所谓的 loop 就是 script 中的一段在一定条件下反覆执行的代码。
bash shell 中常用的 loop 有如下三种:
* for
* while
* until
for loop 是从一个清单列表中读进变量值,并”依次”的循环执行 do 到 done 之间的命令行。
例:
[toggle title="in句式"]
for var in one two three four five do echo ----------- echo '$var is '$var echo done
上例的执行结果将会是:
1) for 会定义一个叫 var 的变量,其值依次是 one two three four five 。
2) 因为有 5 个变量值,因此 do 与 done 之间的命令行会被循环执行 5 次。
3) 每次循环均用 echo 产生三行句子。
而第二行中不在 hard quote 之内的 $var 会依次被替换为 one two three four five 。
4) 当最后一个变量值处理完毕,循环结束。
我们不难看出,在 for loop 中,变量值的多寡,决定循环的次数。
然而,变量在循环中是否使用则不一定,得视设计需求而定。
倘若 for loop 没有使用 in 这个 keyword 来指定变量值清单的话,其值将从 $@ (或 $* )中继承:
for var; do .... done
[/toggle]
for loop 用于处理”清单”(list)项目非常方便,
其清单除了可明确指定或从 positional parameter 取得之外,
也可从变量替换或命令替换取得… (再一次提醒:别忘了命令行的”重组”特性﹗)
然而,对于一些”累计变化”的项目(如整数加减),for 亦能处理:
for ((i=1;i<=10;i++)) do echo "num is $i" done
除了 for loop ,上面的例子我們也可改用 while loop 來做到:
num=1 while [ "$num" -le 10 ]; do echo "num is $num" num=$(($num + 1)) done
while loop 的原理与 for loop 稍有不同:
它不是逐次处理清单中的变量值,而是取决于 while 后面的命令行之 return value :
* 若为 ture ,则执行 do 与 done 之间的命令,然后重新判断 while 后的 return value 。
* 若为 false ,则不再执行 do 与 done 之间的命令而结束循环。
分析上例:
1) 在 while 之前,定义变量 num=1 。
2) 然后测试(test) $num 是否小于或等于 10 。
3) 结果为 true ,于是执行 echo 并将 num 的值加一。
4) 再作第二轮测试,此时 num 的值为 1+1=2 ,依然小于或等于 10,因此为 true ,继续循环。
5) 直到 num 为 10+1=11 时,测试才会失败… 于是结束循环。
我们不难发现:
* 若 while 的测试结果永远为 true 的话,那循环将一直永久执行下去:
while :; do echo looping... done
一旦你能够理解 while loop 的话,那,就能理解 until loop :
* 与 while 相反,until 是在 return value 为 false 时进入循环,否则结束。
因此,前面的例子我们也可以轻鬆的用 until 来写:
num=1 until [ ! "$num" -le 10 ]; do echo "num is $num" num=$(($num + 1)) done
或是
num=1 until [ "$num" -gt 10 ]; do echo "num is $num" num=$(($num + 1)) done
(19)break与continue(与C相同)
这两个命令常用在複合式循环裡,也就是在 do … done 之间又有更进一层的 loop ,
当然,用在单一循环中也未尝不可啦… ^_^
break 是用来打断循环,也就是”强迫结束” 循环。
若 break 后面指定一个数值 n 的话,则”从裡向外”打断第 n 个循环,
预设值为 break 1 ,也就是打断当前的循环。
在使用 break 时需要注意的是, 它与 return 及 exit 是不同的:
* break 是结束 loop
* return 是结束 function
* exit 是结束 script/shell
而 continue 则与 break 相反:强迫进入下一次循环动作。
若你理解不来的话,那你可简单的看成:在 continue 到 done 之间的句子略过而返回循环顶端…
与 break 相同的是:continue 后面也可指定一个数值 n ,以决定继续哪一层(从裡向外计算)的循环,
预设值为 continue 1 ,也就是继续当前的循环。
在 shell script 设计中,若能善用 loop ,将能大幅度提高 script 在複杂条件下的处理能力。
请多加练习吧….
(20)[^ ] 跟 [! ]
通配符(wildcard)知识,暂不记录
“^”是正则表达式中符号,”!”是通配符中的符号,都表示”非”
(21)eval
eval是完成命令重组后再一次重组
a=1 A1=abc eval echo $A$a
(22)正则表达式
正则表达式(Regular Expression)知识,暂不记录
(23)grep与egrep与fgrep区别
* grep:
传统的 grep 程式, 在没有参数的情况下, 只输出符合 RE 字串之句子. 常见参数如下:
-v: 逆反模示, 只输出”不含” RE 字串之句子.
-r: 递迴模式, 可同时处理所有层级子目录裡的文件.
-q: 静默模式, 不输出任何结果(stderr 除外. 常用以获取 return value, 符合为 true, 否则为 false .)
-i: 忽略大小写.
-w: 整词比对, 类似 <word> .
-n: 同时输出行号.
-c: 只输出符合比对的行数.
-l: 只输出符合比对的文件名称.
-o: 只输出符合 RE 的字串. (gnu 新版独有, 不见得所有版本都支持.)
-E: 切换为 egrep .
* egrep:
为 grep 的扩充版本, 改良了许多传统 grep 不能或不便的操作. 比方说:
- grep 之下不支持 ? 与 + 这两种 modifier, 但 egrep 则可.
- grep 不支持 a|b 或 (abc|xyz) 这类”或一”比对, 但 egrep 则可.
- grep 在处理 {n,m} 时, 需用 { 与 } 处理, 但 egrep 则不需.
诸如此类的… 我个人会建议能用 egrep 就不用 grep 啦… ^_^
* fgrep:
不作 RE 处理, 表达式仅作一般字串处理, 所有 meta 均失去功能.