Shell 是一个可以执行命令/程序/shell 脚本的环境,提供了访问 Unix 系统的接口。其根据输入执行程序,执行完成后将结果展示出来。 Shell
.1. variable
变量
- 只读变量
readonly variable
unset {variable_name}
重置一个变量,只读变量不可重置,重置后不能再访问- 变量类型
- Local variable.存在于当前shell实例中的变量,shell开启程序后,程序不能访问local variable .
- Environment variable. 环境变量,shell进程中任何地方可以获取环境变量.
- Shell variable.shell脚本中定义的变量,可以是 local variable ,也可是Environment variable .
.2. Basic operators
.2.1. Arithmetic operators
- 使用基础运算符时引用变量需要同样使用
$
符号,但赋值时直接使用变量名即可。expr a = $b
- 运算符与表达式之间需要空格分开。
expr $a != $b
*
乘号使用需要添加转义\*
- 条件表达式使用需要被方括号(括号与表达式之间需要空格分隔)所包围:
[ $a == $b ]
.2.2. Relational Operators
- 同样需要方括号与空格包围变量
[ $a -eq $b ]
-eq
equals-ne
not equals-gt
greater than-lt
less than-ge
greater or equals-le
less or equals- 关系运算符支付数值类,如果是string类必须是代表数值的string,eg:
"100"
.2.3. Boolean Operators
!
取反-o
OR-a
AND- eg:
[ $a -gt 100 -a $b -le 20 ]
.2.4. String Operators
=
!=
-z
zero 检测字串其长度是否为 0[ -z $a ]
-n
not-zero 字串长度不为 0[ -n $a ]
- str 检测字串是否为 empty
[ $a ]
.2.5. File Test Operators
检测关联到文件的变量属性。假如一个变量 file
关联到一个 test 文件,大小100bytes,有 read/write/execute 权限。其相关命令如下:
-b file
check if file is a block special file.[ -b $file ]
false-c file
check if file is a character special file.[ -c $file ]
false-d file
check if file is a directory.[ -d $file ]
false-f file
check if file is an ordinal file as opposed to a directory or special file.[ -f $file ]
is true-e file
check if file exists.[ -e $file ]
is true-r
/-w
/-x
check if file is readable/writable/executable.
.3. Decision Making
shell 中两种类似 switch case 的分支语句:
- if…elif…else…fi
- case…esac
.4. Process Control
- until 与 while 中的条件相反,满足条件在 while中循环,而不满足条件才在 until 中循环。
break n
跳出循环,其中 n 代表正整数,默认不写为 1 只跳出当前层循环,而如果需要跳出第二层循环(从内往外数)就指定 n 为 2 。
.5. Substitutions
转义
常用转义符号:
\n
new line\r
carriage return\t
horizontal tab\\
back slash\a
alert\b
backspace\c
suppress trailing line\f
form feed\v
vertical tab
.5.1. Command Substitution
command
使用 back quote 将命令包围起来,命令执行结果将返回。eg: echo “today is date
“
.5.2. Variable Substitution
变量转义
使用变量转义可以将对变量进行检查,并对其返回值或变量作修改。
${var:-word}
如果变量 var 为 null 或未设置,将使用 word 转义为结果, var 变量不会被设置成 word.${var}
转义 var 的值${var:=word}
转义 var 并将 word 赋值给 var。${var:?message}
如果 var 未设置或为 null ,message 将打印到 standard error。用以检测变量 var 是否正确设置。${var:+word}
如果 var 已设置,work 将转义给 var ,但 var 不会改变。
.6. Quoting Mechanisms
.6.1. Meta Characters
Unix 元字符在 shell 中有特殊含义,所以在命令中如果要使用其为普通字串,需要在其前加上转义符号 backslash
\
。 Unix 中的元字符包括:
1 | * ? [ ] ' " \ $ ; & ( ) | ^ < > new-line space tab |
?
代表任何一个字符,而 *
代表任意多个字符。
.6.2. quoting
引用方式有四种
- 单引号引用
'
,特殊符号会将全部的元字符给转义为字面量。当需要输出单引号时,此时可以使用 backslash 将其转义输出。 - 双引号引用
"
,大部分特殊符号被双引号引用有将丢失其特殊意义,但有例外:$ ` $ ' " \ - backslash
\
, 所有特殊变量在 backslash 后都将丢失其特殊意义 - back quote `, 被 back quote 包围的任何字符都将会被当作命令执行。
.7. IO Redirection
IO 重定向
重定向的命令有:
pgm > file
重定向到输出文件pgm >> file
将输出追加到指定文件pgm < file
程序从文件读取输入n > file
将 n fd 的流输出重定向到文件 filen >> file
将 fd n 的流输出重定向追加到文件 filen >& m
合并 fd n 流与 fd m 流输出n <& m
合并输入流 fd n 与 fd m<< tag
Standard input comes from here through next tag at the start of line|
管道,将前一个程序/应用的输出发送到下一个
NOTE: file descriptor(fd) 在 Unix 中使用非负整数表示,其中 0 表示标准输入 STDIN,1 表示标准输出 STDOUT,2 表示错误输出 STDERR
在 Unix 系统中每个非守护进程都有以上三个 IO 流,进程通过 kernel 访问文件 file table / inode table。
在脚本中实现交互
- 使用重定向
- 使用管道
- 使用 expect (需要安装此功能)
.8. Functions
Unix shell function
- 定义 function 其语法是:在方法名后跟上
function_name () {}
,传递参数直接在命令行中添加,在方法中调用参数使用$n
- 返回数据使用关键字
return
exit
会终结整个 shell 执行,而不是 function 。$?
获取上一次命令返回值ret=$?
,此值只是一个整数代表结果,不能返回字符及其他- shell 文件调用需要使用
. shell_file
- shell 文件后缀可以不用写,一样的效果
- shell 文件头指定 shell 执行 bash 类型也可不写,让系统默认的 shell 执行即可
echo $PATH
可以看到系统全局变量,其中一般包括了 ~/bin ,所以要以在此文件路径中添加自己想要的全局 shell ,而实现任何地方不添加绝对路径前缀调用此 shell 。$HOME
调用当前用户目录,在 shell 中使用 ~ 不会生效。
.9. Alias
给 bash shell 命令添加别名.reference
- 使用命令
alias command='command arguments'
给命令添加别名,从而缩小写常用参数的工作。eg:alias grep='grep -iE --color=auto'
,可以实现使用 grep 命令自动添加两个参数 - 如果要永久实现别名生效可以将命令添加到 ~/.bashrc 文件中并执行此文件
- 解除别名设置使用命令
unalias name
.10. 添加机器命令别名与进入日志脚本
1 | !/bin/bash |
.11. Questions
.11.1. Shell 脚本中 cd 命令不生效
再现:在 l 脚本中写了 cd 命令,再放在 PATH 中,在 terminal 直接调用这个脚本 l
,发现当前目录还是原目录并未进入到脚本中指定的目录。
原因:在接 terminal 调用脚本,是在当前 shell 环境中执行另外一个进程,进程结束就返回了原 shell 。
解决:使用 source
或 .
命令在当前 shell 中执行脚本,而不是直接调用脚本。