Shell脚本学习笔记
文章目錄
以前多多少少接触过一些shell命令,用的不多,现在打算好好了解一下。看了Linux Shell脚本教程,这里做点笔记:
Shell 在线环境
几种常见的Shell
- bash: Linux标准默认的shell,内部命令一共有40个。
- sh: Unix 标准默认的shell。
- …
bash完全兼容sh,也就是说,用sh写的脚本可以不加修改的在bash中执行。
不使用Shell的情况
- 资源密集型的任务,尤其在需要考虑效率时(比如,排序,hash等等)。
- 需要处理大任务的数学操作,尤其是浮点运算,精确运算,或者复杂的算术运算(这种情况一般使用C++或FORTRAN 来处理)。
- 有跨平台(操作系统)移植需求(一般使用C 或Java)。
- 复杂的应用,在必须使用结构化编程的时候(需要变量的类型检查,函数原型,等等)。
- 对于影响系统全局性的关键任务应用。
- 对于安全有很高要求的任务,比如你需要一个健壮的系统来防止入侵、破解、恶意破坏等等。
- 项目由连串的依赖的各个部分组成。
- 需要大规模的文件操作。
- 需要多维数组的支持。
- 需要数据结构的支持,比如链表或数等数据结构。
- 需要产生或操作图形化界面 GUI。
- 需要直接操作系统硬件。
- 需要 I/O 或socket 接口。
- 需要使用库或者遗留下来的老代码的接口。
- 私人的、闭源的应用(shell 脚本把代码就放在文本文件中,全世界都能看到)
Shell脚本
“#!”
是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种Shell。变量
- 变量名和等号之间不能有空格。
- 定义变量时,变量名不加美元符号($);使用一个定义过的变量,只要在变量名前面加美元符号($)即可。
- 变量名外面的花括号是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界。建议使用时在所有变量外加花括号。
- 使用readonly命令可以将变量定义为只读变量,只读变量的值不能被改变。
- 使用unset命令可以删除变量。
- 变量类型:
- 局部变量:在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量。
- 环境变量:所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候shell脚本也可以定义环境变量。
- shell变量:由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行。
- 特殊变量:
$0
当前脚本的文件名$n
传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是$1,第二个参数是$2。$#
传递给脚本或函数的参数个数。$*
传递给脚本或函数的所有参数。$@
传递给脚本或函数的所有参数。被双引号(“ “)包含时,与 $* 稍有不同,下面将会讲到。$?
上个命令的退出状态,或函数的返回值。$$
当前Shell进程ID。对于 Shell 脚本,就是这些脚本所在的进程ID。
$*
和$@
的区别$ 和 $@ 都表示传递给函数或脚本的所有参数,不被双引号(“ “)包含时,都以”$1” “$2” … “$n” 的形式输出所有参数。但是当它们被双引号(“ “)包含时,”$“ 会将所有的参数作为一个整体,以”$1 $2 … $n”的形式输出所有参数;”$@” 会将各个参数分开,以”$1” “$2” … “$n” 的形式输出所有参数.
Shell替换
echo
命令的 -e 表示对转义字符进行替换,-E 选项禁止转义,默认也是不转义的;使用 -n 选项可以禁止插入换行符。- 变量替换
${var}
变量本来的值${var:-word}
如果变量 var 为空或已被删除(unset),那么返回 word,但不改变 var 的值。${var:=word}
如果变量 var 为空或已被删除(unset),那么返回 word,并将 var 的值设置为 word。${var:?message}
如果变量 var 为空或已被删除(unset),那么将消息 message 送到标准错误输出,可以用来检测变量 var 是否可以被正常赋值。
若此替换出现在Shell脚本中,那么脚本将停止运行。${var:+word}
如果变量 var 被定义,那么返回 word,但不改变 var 的值。
注释
- 只有单行注释,用
#
- 如果在开发过程中,遇到大段的代码需要临时注释起来,可以把这一段要注释的代码用一对花括号括起来,定义成一个函数,没有地方调用这个函数,这块代码就不会执行。
- 只有单行注释,用
字符串
- 单引号:单引号字符串中的变量是无效的;单引号字串中不能出现单引号(对单引号使用转义符后也不行)。
- 双引号:双引号里可以有变量,双引号里可以出现转义字符。
- 获取字符串长度:
${#string} #输出 4``` 1
- 提取子字符串: ```echo ${string:1:4} #输出liba
数组
- 用括号表示
- 使用@ 或 * 可以作下标获取数组中的所有元素
printf命令
与C语言中的
printf
的不同:- 不用加括号
- 参数的分隔用空格,不是逗号
- 格式字符串能重用,可以将所有参数都转换
case … esac
- 类似于C中的
switch ...case...
语句 - 取值后面必须为关键字 in,每一模式必须以右括号结束
;;
与其他语言中的 break 类似*
类似于default
,捕捉其他情况
- 类似于C中的
运算符
expr
:- 注意表达式和运算符之间要有空格;
- 乘号(*)前边必须加反斜杠()才能实现乘法运算。
关系运算符:只支持数字,不支持字符串,除非字符串的值是数字。
- 布尔运算符:
!
非运算-o
或运算-a
与运算
字符串运算符:
=
检测两个字符串是否相等;算数运算符的相等比较用==
!=
检测两个字符串是否相等-z
检测字符串长度是否为0-n
检测字符串长度是否为0str
检测字符串是否不为空
文件测试运算符:
-b file
检测文件是否是块设备文件,如果是,则返回 true。 [ -b $file ] 返回 false。-c file
检测文件是否是字符设备文件。-d file
检测文件是否是目录。-f file
检测文件是否是普通文件(既不是目录,也不是设备文件)。-g file
检测文件是否设置了 SGID 位。-k file
检测文件是否设置了粘着位(Sticky Bit)。-p file
检测文件是否是具名管道。-u file
检测文件是否设置了 SUID 位。-r file
检测文件是否可。-w file
检测文件是否可写。-x file
检测文件是否可执行。-s file
检测文件是否不为空(文件大小是否大于0)。-e file
检测文件(包括目录)是否存在。
break命令
- 跳出循环,不跳出case
- 在嵌套循环中,break 命令后面还可以跟一个整数,表示跳出第几层循环
函数
- 定义函数时,函数名前加上关键字
function
可有可无 - 可以显式增加return语句;如果不加,会将最后一条命令运行结果作为返回值
- 调用函数只需要给出函数名,不需要加括号
- 删除函数也可以使用
unset
命令,不过要加上 .f 选项 - 将函数定义在主目录下的 .profile 文件,这样每次登录后,在命令提示符后面输入函数名字就可以立即调用
- 定义函数时,函数名前加上关键字
输入输出重定向
command > file
将输出重定向到 file。command < file
将输入重定向到 file。command >> file
将输出以追加的方式重定向到 file。n > file
将文件描述符为 n 的文件重定向到 file。n >> file
将文件描述符为 n 的文件以追加的方式重定向到 file。n >& m
将输出文件 m 和 n 合并。n <& m
将输入文件 m 和 n 合并。<< tag
将开始标记 tag 和结束标记 tag 之间的内容作为输入。/dev/null 文件是一个特殊的文件,写入到它的内容都会被丢弃;如果尝试从该文件读取内容,那么什么也读不到.
文件包含
- Shell 中包含脚本可以使用:
. filename
或source filename
- 被包含脚本不需要有执行权限
- Shell 中包含脚本可以使用: