shell编程中的 三种结构: 条件if/选择结构case/循环for/while/until等结构 和 函数的用法
shell 函数的使用 (md中, 列表本身是有格式的, 他要产生缩进, 其次,列表项和列表项之间, 可以留有一个空行, 是合法的, 允许的)
-
shell函数,就是 就相当于一个命令来看待和处理的, 这有助于shell解释器的写法. 在调用方法上, 跟 命令的方式是一样的, 也是
函数名 arg1 arg2 ...
函数名就相当于命令名. 对于一个命令来说, 格式是:ls /etc 命令名 [options] arg...
所以函数也是一样funcName arg1 arg2 ...
, 这里的函数名称后面, 不要加括号.
函数的定义上, 可以加function关键字, 也可以不加. 括号中也不用写形参, 因为在调用函数的时候, 传递的参数就直接 默认的作为函数定义中的第一个形参, 第二个形参... 所以函数定义的时候, 在函数体中, 可以直接使用$1, $2, ..., 还有$0, $#, $*, $@ 等特殊变量. -
相对来说, 定义函数的语法还是比较宽松的, 只是 大括号前后 应该和其他单词 有一个空格.
在shell编程中,避免出错的秘诀就是, 一是, 不能像 C /java等高级语言中, 符号之间没有严格的分隔. 要避免shell脚本出错, 最好是 每个单词("每个语义上的单词") 之间 用空格隔开, 便于shell解释器 解析; 二是, 要时常有这样的思想: 假设你是shell的解释器, 你会怎样来解释. 要知道shell解析一条语句的方式, 如果没有检测到builtin命令或外部命令的时候,总是企图把她解析为 一个命令. 或者, 如果解析到了builtin或外部命令, 后面的内容如果不用空格分隔, 就会解析成一个 整的字符串!
-
关于函数和各种结构语句的写法
结构语句可以分成多行来写, 也可以放在一行来写, 如果一行来写, 就要使用** C 语言的语法**, 每条语句后面都必须跟一个分号. 包括最后一个done语句
变量\(的扩展,必须放在双引号中, 如果是单引号, 不会扩展\), 只会当作一个普通字符来对待, 所以在表示变量的值的场合, 如 case "$read" in中, 要用双引号.
-
关于选择结构(分支结构)的使用
shell只的选择结构使用的是 case语句, 而不是C 语言只的switch .. case. 它直接就是case语句,没有switch.
表示分支的,用 "一个)" 来表示, 注意不是两个)), 是用两个分号;; 来代替C 语言中的break.
case 的结束符号是 esac: [i's2k]
case每一种情况中, 支持"分组 和 多选一" : 分组 只能用 | 表示, 多选一, 只能用中括号表示, 这两种不能混用, 即多选一中不能用分组, 分组也不能使用小括号.
- 在if for while until case 语句中, 哪些部分表示一个语句/分句?
if: if...; then ...; fi; 由3个分句组成, then后面的内容是一个分句, 不要加分号
for,while等: for...; do ...; done; 由3个分句组成, do后面的内容是一个分句, 不要加分号
case: case "$read" in 1) ...;; 2)...;; *)...;; esac; 在第一种情况前都是第一个分句, 即in前后都是一个分句, 不要加分号
对于字符串变量, 建议要加上双引号, 其实加不加双引号都无所谓, 因为shell中的变量默认都是字符串, 除非你用let, expr命令, 才能进行四则运算
let可以执行多个表达式( 1+1可以是表达式, 赋值也是表达式如a=1+2) 多个表达式之间用空格 隔开, 注意不是用逗号隔开. 如: let 1+1 0+0
是正确的命令
let 计算表达式的值, 如果你不把表达式的值付给 变量, 这个值将会被丢弃.
**let有返回值, 它返回的是 最后一个表达式的值, 如: let 1+1 0+0 将返回0, 而let 0+0 1+1 则返回的是非0 **
let会自动检查是否是整数, 否则会出错.
特别注意的是, 在所有的..赋值表达式中, 等号左边的符号都应该是一个变量, 不能是\(var, 因为\)var会替换, 它是一个具体的数值. 给数值赋值, 会报错: assign a non-variable .
同时, 在任意一门编程语言中, 都可以用&& || 来代替简单的 if else fi.
单括号和双括号的区别?
单括号可以代替 [ 命令, 来执行判断;
双括号则可以代替 let命令来进行整数运算. 当然双括号可以横扫一切的判断和循环语句中的条件表达式
trap <command> exit: trap的格式: trap "commands" signal-list
是提供进程间的通信机制. 一个进程是当前进程, 当前执行trap命令的这个进程; 另外的进程, 是发送 signal-list中的进程或操作/终端等.
trap提供应用程序提供一种异步的软件中断, 使应用程序有机会接受其他程序和 终端2发送的命令(即信号). 应用程序收到信号后, 有三种处理方式: SIG_IGN, 忽略该信号; SIG_DFT采取系统默认的处理方式, 通常是终止进程或忽略; 如果给该信号指定了一个处理函数(捕捉), 则会中断当前进程正在执行的任务, 转而去执行该信号的处理函数, 返回后再继续执行被中断的任务.
trap "commands" SIGNALS
trap意思是捕捉, 就是说 cpu(系统) 去捕捉后面的signal-list中的信号, 一旦捕捉到了之后, 就会暂时中断当前的事(放下...), 去执行 commands... 执行完了之后, 返回当前进程(通常是shell) , 然后再去执行 当前被中断的事情.
信号有: HUP(hang up挂起), INT(interrupt中断), QUIT(退出)等.
#!/bin/bash
times=1
while [ 1 ]
do
echo "this time is $times "
trap "exit" INT // 按ctrl-c中断信号, 执行exit.
let times++
done
unset times
~
~
~
~
在shell语句中, 独立的单词与单词 之间, 分号与单词之间, 他们中间的空格是可以任意多个的. 但是除此之外, **凡是符号/括号, 包括单双大中小 括号, 与其中的 内容, 中间的空格是 严格要求的: 有的空格是必须的, 如 [, 而有的空格又是不能要的 , 如: 大括号中的数字范围 {1..10}
for的结构类型包括
第一. for 后面是一个列表, 是多个离散的数字值时
-
for i in 1 2 3 ; do echo $i; done
// 一般后面的项比较少时, 可以这样列举 -
for i in {1..10}; do echo $i; done
// 这里注意两个问题, 一是表示 "到, 范围的符号是 .., 而不是冒号", 另外, 使用的是大括号, 而不是双小括号, 并且大括号和数字之间不能有空格. -
使用seq命令: seq是按照steps [INCREMENT] 产生一些列数字
注意的是, /usr/bin/seq 命令中的 increment 是放在 first 和 last之间的, 不是放在最后的! 同时, 由于seq 是命令, 因此, 在 for后面要 用 反引号或 小括号 括起来.
-
使用双括号括起来, 类似c语言的语法:
for ((i=0; i<10; i++)) ; do echo $i ; done
第二. for 后面循环的 是文件时. 通常有两种命令, 一是 ls , 二是 find命令:
for file in `ls *.sh` ; do echo
第三, for 打印basename文件名:
首先注意, basename是一个 shell的命令, 不是函数:
![](https://images2015.cnblogs.com/blog/821299/201705/821299-20170531101340836-42455682.png)
其次, basenanme的suffix是可以自己随意指定的, 不一定就是点号后面的部分
![](https://images2015.cnblogs.com/blog/821299/201705/821299-20170531101519649-1325012528.png)
然后, suffix可以放在最后, 也可以用-s(--suffix)放在basename后面, 作为options看待.
![](https://images2015.cnblogs.com/blog/821299/201705/821299-20170531101110836-1597651206.png)
until循环
until很简单,只要记住它与while正好相反即可,即条件为假继续执行,条件为真,就跳出循环。
注意for循环和shift.
shift: 一句话, 删除\(@ 或\)*队列中的第一个参数. 这样, \(#总数减少一, 同时原来的参数\)i 依次就等于其后面的 $i+1, 即: $1=$2, $2=$3等等.