什么时候不适合使用Shell脚本
- 资源密集型的任务,尤其在需要考虑效率时(比如,排序,hash等等)
- 需要处理大任务的数学操作,尤其是浮点运算,精确运算,或者复杂的算术运算(这种情况一般使用C++或FORTRAN来处理)
- 有跨平台移植需求(一般使用C或Java)
- 复杂的应用,在必须使用结构化编程的时候(需要变量的类型检查,函数原型,等等)
- 至关重要的应用,比如说为了这个应用,你需要赌上自己的农场,甚至赌上你们公司的未来
- 对于安全有很高要求的任务,比如你需要一个健壮的系统来防止入侵,破解,恶意破坏等等
- 工程的每个组成部分之间,需要连锁的依赖性
- 需要大规模的文件操作(Bash受限于顺序地进行文件访问,而且只能使用这种笨拙的效率低下的一行接一行的处理方式)
- 需要多维数组的支持
- 需要产生或操作图形化界面GUI
- 需要直接操作系统硬件
- 需要I/O或socket接口
- 需要使用库或者遗留下来的旧代码的接口
- 个人的,闭源的应用(shell脚本把代码就放在文本文件中,全世界都能看到)
- # 注释
- ; 命令分隔符
- ;; 终止case选项
- . "点"命令,等价于source命令,这是一个bash的内建命令,如果点放在文件名的开头,这个文件将成为隐藏文件,ls不会正常显示该文件,还可用作字符匹配
- " 部分引用
- ' 全引用
- , 逗号操作符
- \ 转义符
- / 文件名路径分隔符
- 、命令替换
- : 空命令
- ! 取反操作符
- * 通配符,也可用做算术操作符
- ? 测试操作符,用来测试一个条件的结果,也可用作通配符
- $ 变量替换(引用变量的内容),在正则表达式中表示行结束符
- ${} 参数替换
- $*,$@ 位置参数
- $? 退出状态码变量
- $$ 进程ID变量
- () 命令组
- {} 代码块
- {} \: 路径名
- [] 条件测试
- [[ ]] 测试
- [] 数组元素,在正则表达式中描述一个匹配的字符范围
- (( )) 整数扩展
- > &> >& >> < <> 重定向 进程替换
- << 用在here document中的重定向
- <<< 用在here string中的重定向
- <, > ASCII comparison
- \<, \> 正则表达式中的单词边界
- | 管道 分析前边命令的输出,并将输出作为后边命令的输入,这是一种产生命令链的好办法
- >| 强制重定向
- || 或逻辑操作
- & 后台运行命令
- && 与逻辑操作
- - 选项,前缀,在所有的命令内如果想使用选项参数的话,前边都要加上"-",也可用于重定向stdin或stdout,cd -将会回到先前的工作目录,用作算术操作时是减号
- = 等号 赋值操作
- + 加号 算术操作
- + 选项 一个命令或者过滤器的选项标记
- % 取模 算术操作
- ~ home目录
- ~+ 当前工作目录
- ~- 先前工作目录
- =~ 正则表达式匹配
- ^ 行首
控制字符
- C-B 退格(不删掉前面的字符)
- C-C break 终止一个前台作业
- C-D 从一个shell中登出,类似exit
- C-G “哔”(beep)
- C-H 退格(破坏性)
- C-I 水平制表符
- C-J 重起一行
- C-K 垂直制表符
- C-L 清屏
- C-M 回车
- C-Q 恢复,在一个终端中恢复stdin
- C-S 挂起,冻结stdin
- C-U 删除光标到行首的所有字符
- C-V 当输入字符时,允许插入控制字符
- C-W 删除当前光标到左边最近一个空格间的全部字符
- C-Z 暂停前台作业
空白 用来分隔函数,命令或变量,包含空格,tab,空行或者它们之间任意的组合体
变量的名字就是变量保存值的地方. 引用变量的值就叫做变量替换
echo和sed命令中使用
\n
表示新的一行
\r
表示回车
\t
表示水平制表符
\v
表示垂直制表符
\b
表示后退符
\a
表示"alert"(蜂鸣或者闪烁)
\$
表示$本身子面的含义(跟在\$后边的变量名将不能引用变量的值)
\\
表示反斜线字面的意思
如果下面的条件成立将会返回真.
-e
文件存在
-a
文件存在
这个选项的效果与-e相同. 但是它已经被"弃用"了, 并且不鼓励使用.
-f
表示这个文件是一个一般文件(并不是目录或者设备文件)
-s
文件大小不为零
-d
表示这是一个目录
-b
表示这是一个块设备(软盘, 光驱, 等等.)
-c
表示这是一个字符设备(键盘, modem, 声卡, 等等.)
-p
这个文件是一个管道
-h
这是一个符号链接
-L
这是一个符号链接
-S
表示这是一个socket
-t
文件(描述符)被关联到一个终端设备上
这个测试选项一般被用来检测脚本中的stdin([ -t 0 ]) 或者stdout([ -t 1 ])是否来自于一个终端.
-r
文件是否具有可读权限(指的是正在运行这个测试命令的用户是否具有读权限)
-w
文件是否具有可写权限(指的是正在运行这个测试命令的用户是否具有写权限)
-x
文件是否具有可执行权限(指的是正在运行这个测试命令的用户是否具有可执行权限)
-g
set-group-id(sgid)标记被设置到文件或目录上
如果目录具有sgid标记的话, 那么在这个目录下所创建的文件将属于拥有这个目录的用户组, 而不必是创建这个文件的用户组. 这个特性对于在一个工作组中共享目录非常有用.
-u
set-user-id (suid)标记被设置到文件上
对于设置了suid标志的文件, 在它的权限列中将会以s表示.
-k
设置粘贴位
-O
判断你是否是文件的拥有者
-G
文件的group-id是否与你的相同
-N
从文件上一次被读取到现在为止, 文件是否被修改过
f1 -nt f2
文件f1比文件f2新
f1 -ot f2
文件f1比文件f2旧
f1 -ef f2
文件f1和文件f2是相同文件的硬链接
!
"非" -- 反转上边所有测试的结果(如果没给出条件, 那么返回真).
二元比较操作符用来比较两个变量或数字. 注意整数比较与字符串比较的区别.
整数比较
-eq
等于
if [ "$a" -eq "$b" ]
-ne
不等于
if [ "$a" -ne "$b" ]
-gt
大于
if [ "$a" -gt "$b" ]
-ge
大于等于
if [ "$a" -ge "$b" ]
-lt
小于
if [ "$a" -lt "$b" ]
-le
小于等于
if [ "$a" -le "$b" ]
<
小于(在双括号中使用)
(("$a" < "$b"))
<=
小于等于(在双括号中使用)
(("$a" <= "$b"))
>
大于(在双括号中使用)
(("$a" > "$b"))
>=
大于等于(在双括号中使用)
(("$a" >= "$b"))
字符串比较
=
等于
if [ "$a" = "$b" ]
==
等于
if [ "$a" == "$b" ]
与=等价.
==比较操作符在双中括号对和单中括号对中的行为是不同的.
1 [[ $a == z* ]] # 如果$a以"z"开头(模式匹配)那么结果将为真
2 [[ $a == "z*" ]] # 如果$a与z*相等(就是字面意思完全一样), 那么结果为真.
3
4 [ $a == z* ] # 文件扩展匹配(file globbing)和单词分割有
效.
5 [ "$a" == "z*" ] # 如果$a与z*相等(就是字面意思完全一样), 那
么结果为真.
6
7 # 感谢, Stephane Chazelas
!=
不等号
if [ "$a" != "$b" ]
这个操作符将在[[ ... ]]结构中使用模式匹配.
<
小于, 按照ASCII字符进行排序
if [[ "$a" < "$b" ]]
if [ "$a" \< "$b" ]
注意"<"使用在[ ]结构中的时候需要被转义.
>
大于, 按照ASCII字符进行排序
if [[ "$a" > "$b" ]]
if [ "$a" \> "$b" ]
注意">"使用在[ ]结构中的时候需要被转义.
参考例子 26-11, 这个例子展示了如何使用这个比较操作符.
-z
字符串为"null", 意思就是字符串长度为零
-n
字符串不为"null"-a
逻辑与
exp1 -a exp2 如果表达式exp1和exp2都为真的话, 那么结果为真.
-o
逻辑或
exp1 -o exp2 如果表达式exp1和exp2中至少有一个为真的话, 那么结果为真.
位操作符
<<
左移一位(每次左移都相当于乘以2)
<<=
"左移-赋值"
let "var <<= 2" 这句的结果就是变量var左移2位(就是乘以4)
>>
右移一位(每次右移都将除以2)
>>=
"右移-赋值" (与<<=正好相反)
&
按位与
&=
"按位与-赋值"
|
按位或
|=
"按位或-赋值"
~
按位反
!
按位非
^
按位异或XOR
^=
"按位异或-赋值"