Hello World
  | 
  | 
文件保存为hello.sh,然后修改文件的权限:
  | 
  | 
最后,执行:
  | 
  | 
exit不是必须的,但是每个命令都会返回一个退出状态给父进程,成功返回0,非0值通常被认为是错误码,良好脚本都会带上exit,当一个脚本不带参数exit来结束时,脚本的退出状态由脚本中最后执行命令来决定
echo $?可以用来查看前一个命令的退出状态
赋值
使用=进行赋值,并且=左右两边不能有空格,获取变量值得时候在变量名前面加$
  | 
  | 
变量
  | 
  | 
正如所见,变量替换会去除掉空白,全引用会禁止所有特殊符号,如果只是想输出变量的值,推荐使用"${}"这种形式
bash中变量的类型
  | 
  | 
所以说bash中的变量都是无类型的
特殊变量
  | 
  | 
1 2 3 4 5 6 7 8 9 10是从命令行传入的10个参数,$0表示脚本名称,$1表示第一个参数,${10}表示第10个参数,$#位置参数的个数,$*所有的位置参数,被作为一个单词
每一次执行shift命令能够将所有位置参数向前移动一个位置,而原来第一个位置的参数则被丢弃
内部变量
$BASH - bash二进制执行文件的位置
$FUNCNAME - 当前函数的名字
$GROUPS - 当前用户属于的组
$HOME - 用户home目录
$HOSTNAME - 主机名
$IFS - 内部域分隔符,该变量决定bash在解释字符串时如何识别域或单词的边界
$LINENO - 记录它所在shell脚本中它所在行的行号
$OSTYPE - 系统类型
$PPID - 一个进程的$PPID就是它的父进程的pid
$PWD - 当前工作目录
$SECONDS - 这个脚本已经运行的时间
$SHLVL - shell层叠的层次
$UID - 用户id号
$$ - 脚本自身进程pid
获取变量名
  | 
  | 
这两个命令都可以返回以prefix开头的已有变量
Here Documents
here documents是一种重定向的形式
  | 
  | 
这里的command是一个可以接受标准输入的命令,token是一个用来指示嵌入文本结束的字符串。上述结构就是将text的内容当作标准输入传给了command
将<<改为<<-,shell就会忽略text开头的tab字符,这样text内容就可以缩进,从而提高代码的可读性。
  | 
  | 
常用上述方法代替echo输出多行内容
获取用户输入
使用read来获取用户的输入
read a将获取用户的输入到变量a,如果没有提供变量名,默认变量REPLY会包含用户输入
read支持以下选项
-a array - 把输入赋值到数组array中,从索引号0开始
-n num - 读取num个输入字符,而不是整行
-p prompt - 为输入显示提示信息
-r - raw modw,不会把反斜杠字符解释为转义字符
-s - silent mode,不会再屏幕上显示输入的文字
-t seconds  - 超时,seconds秒之后,如果没有输入,则返回一个非零退出状态
给变量指定默认值
  | 
  | 
若parameter没有设置或者为空,展开结果为word,若parameter不为空,则展开结果是parameter的值
  | 
  | 
若parameter没有设置或者为空,展开结果为word,并且word的值会赋值给parameter,若parameter不为空,则展开结果是parameter的值
  | 
  | 
若parameter没有设置或者为空,这种展开导致脚本带有错误退出,并且word的内容会发送到标准错误,若parameter不为空,则展开结果是parameter的值
函数
函数定义
函数定义有两种形式
  | 
  | 
或者
  | 
  | 
调用函数时,只用写函数名,不用加括号,并且函数的定义要在函数调用之前
  | 
  | 
局部变量
在函数内部使用local关键字来定义局部变量
  | 
  | 
if
  | 
  | 
判断
涉及到判断的地方都是检测命令的退出状态码,如果是0,表示命令成功执行,也就表示当前判断的内容为真,非0则假。
文件表达式
-d file - file存在并且是一个目录
-e file - file存在
-f file - file存在并且是一个普通文件
-s file - file存在并且其长度大于0
-r file - file存在并且可读
-w file - file存在并且可写
-x file - file存在并且可执行
  | 
  | 
字符串表达式
-n string - 字符串string的长度大于0
-z string - 字符串string的长度为0
string1 == string2 - 字符串string1等于字符串string2
string1 > string2 - string1排列在string2之后
其他判断
  | 
  | 
类似于test
  | 
  | 
如果string匹配正则表达式regex,则返回真
while
  | 
  | 
循环中可以使用continue和break
循环读取数据
  | 
  | 
  | 
  | 
read每次读取文本行之后将会返回退出状态码0,知道文件末尾,返回状态码非零才结束while循环
当循环终止时,循环中创建的任意变量或赋值的变量都会消失
until
与while类似
  | 
  | 
case
  | 
  | 
匹配模式
a) - 匹配单词a
a|A) - 匹配单词a或A
[[:alpha:]] - 若单词是一个字母字符,则匹配
???) - 若单词只有3个字符,则匹配
*.txt - 若单词以.txt字符结尾,则匹配
for
  | 
  | 
  | 
  | 
  | 
  | 
也可以使用c语言格式:
  | 
  | 
字符串操作
  | 
  | 
会展开为parameter所包含的字符串的长度
  | 
  | 
子串消除
  | 
  | 
  | 
  | 
  | 
  | 
功能与#和##类似,只是是从结尾开始匹配
字符串替换
  | 
  | 
原parameter变量值不变
字符串大小写
  | 
  | 
原parameter变量值不变
数组
  | 
  | 
多值赋值
  | 
  | 
输出整个数组内容
  | 
  | 
下标*和@可以被用来访问数组中的每一个元素
关联数组
  | 
  | 
找到数组使用的下标
bash允许数组下标包含空格,有时候确定哪个元素真正存在是很有用的
  | 
  | 
组命令和子shell
组命令
  | 
  | 
子shell
  | 
  | 
组命令和子shell都是用来管理重定向的
  | 
  | 
会将三个命令的结果合成在一起然后重定向到output.txt中
组命令是在当前shell中执行它所有的命令,而子shell是在一个子shell中执行命令,在子shell中执行命令对环境变量等修改在子shell消失之后便会消失,大多数情况下,我们使用组命令。
  | 
  | 
该REPLY变量的内容总是空,是应为在管道线中的命令总是在子shell中执行的,bash提供进程替换来解决这个问题
进程替换
<(list) - 一种适用于产生标准输出的进程
>(list) - 一种适用于接受标准输入的进程
  | 
  | 
进程替换允许我们把一个子shell的输出结果当作一个用于重定向的普通文件,事实上,它就是一种展开形式