运算符
+ | 加法 | expr $a + $b 结果为 30。 |
---|---|---|
- | 减法 | expr $a - $b 结果为 -10。 |
* | 乘法 | expr $a \* $b 结果为 200。 |
/ | 除法 | expr $b / $a 结果为 2。 |
% | 取余 | expr $b % $a 结果为 0。 |
= | 赋值 | a=$b 将把变量 b 的值赋给 a。 |
== | 相等。用于比较两个数字,相同则返回 true。 | [ $a == $b ] 返回 false。 |
!= | 不相等。用于比较两个数字,不相同则返回 true。 | [ $a != $b ] 返回 true。 |
三元运算
expr1?expr2:expr3
比较(三元组)操作.如果表达式expr1非零(算术为true),那么执行expr2,否则执行expr3
shell内置变量含义
1. $$
Shell本身的PID(ProcessID)
2. $!
Shell最后运行的后台Process的PID
3. $?
最后运行的命令的结束代码(返回值)
4. $-
使用Set命令设定的Flag一览
5. $*
所有参数列表。如"$*"用「"」括起来的情况、以"$1 $2 … $n"的形式输出所有参数。
6. $@
所有参数列表。如"$@"用「"」括起来的情况、以"$1" "$2" … "$n" 的形式输出所有参数。
7. $#
添加到Shell的参数个数
8. $0
Shell本身的文件名
9.$1~$n
添加到Shell的各参数值。$1是第1参数、$2是第2参数…。
!$ 和$_ 的区别
!$
会打印上一行命令的最后一个参数,$_
则会打印上一个命令的最后一个参数(无论是否在同一行内)
!$
示例:
echo 111
echo 222 && echo !$ # 输出上一行命令最后参数 111
echo 111
echo 222 ; echo !$ # 输出上一行命令最后参数 111
!_
示例:
echo 111
echo 222 && echo !_ # 输出上一个命令最后参数 222
echo 111
echo 222 ; echo !_ # 输出上一个命令最后参数 222
赋值操作符
以下示例,在变量不为空时,a=1
格式 | 列子 | 未定义 | 变量为空 | 变量不为空 | 补充 |
---|---|---|---|---|---|
= | echo ${a=2} | 2 | null | 1 | |
:= | echo ${a:=2} | 2 | 2 | 1 | |
:- | echo ${a:-2} | 2 | 2 | 1 | 不会赋值给变量,只有在运行阶段替换${} |
- | echo ${a-2} | 2 | null | null | 不会赋值给变量,只有在运行阶段替换${} |
:? | echo ${a:?2} | 2 | 2 | 1 | 不会赋值给变量,只有在运行阶段替换${}, 变量已被定义但却没有一个真正的值(也就是说非空)或者完全未被定义并且脚本退出执行 |
? | echo ${a?2} | 2 | null | 1 | 如果username变量没有被定义,执行LOGNAME替换, 脚本退出运行,并显示退出时所在代码行在脚本中的位置。 |
:+ | echo ${a:+2} | null | null | 2 | |
+ | echo : ${a+2} | null | 2 | 2 | |
${var} 和 ${!var}
! v a r 是 指 取 变 量 时 变 量 名 从 v a r 中 动 态 得 到 , 而 不 是 直 接 的 字 面 量 v a r 。 v a r 可 以 是 其 它 合 法 的 变 量 名 , 如 {!var}是指取变量时变量名从var中动态得到,而不是直接的字面量var。var可以是其它合法的变量名,如 !var是指取变量时变量名从var中动态得到,而不是直接的字面量var。var可以是其它合法的变量名,如{!aaa}、${!bbb}
- ! v a r 可 以 理 解 为 递 归 取 值 , 获 得 变 量 v a r 的 值 后 , 继 续 取 名 为 {!var} 可以理解为递归取值,获得变量var的值后,继续取名为 !var可以理解为递归取值,获得变量var的值后,继续取名为var的变量的值
f1() {
local var="$1"
echo "${!var}"
}
f1 1 --结果 1,相当于echo "${1}"
f1 2 b --结果 b, 相当于echo "${2}"
- ${var} 取变量var的值
f1() {
local var="$1"
echo "${var}"
}
f1 1 --结果 1
f1 2 b --结果 2
返回变量名
${!var*}
和${!var@}
返回以指定字符串开头的变量名,两个方式效果一样
bash 中的 ${ # % / } 字符串操作符
使用#和%删除字符串
变量: file=/dir1/dir2/dir3/my.file.txt
${ # */ } ${ ## } ${ % } ${ %% }
${file#*/}:删掉第一个 / 及其左边的字符串:dir1/dir2/dir3/my.file.txt
${file##*/}:删掉最后一个 / 及其左边的字符串:my.file.txt
${file#*.}:删掉第一个 . 及其左边的字符串:file.txt
${file##*.}:删掉最后一个 . 及其左边的字符串:txt
${file%/*}:删掉最后一个 / 及其右边的字符串:/dir1/dir2/dir3
${file%%/*}:删掉第一个 / 及其右边的字符串:(空值)
${file%.*}:删掉最后一个 . 及其右边的字符串:/dir1/dir2/dir3/my.file
${file%%.*}:删掉第一个 . 及其右边的字符串:/dir1/dir2/dir3/my
记忆的方法为:
# 是去掉左边(键盘上#在 $ 的左边)
% 是去掉右边(键盘上% 在$ 的右边)
单一符号是最小匹配;两个符号是最大匹配
使用//替换字符串
${var/ / } ${var// / }
// 对变量值里的字符串作替换:
${file/dir/path}:将第一个dir 替换为path:/path1/dir2/dir3/my.file.txt
${file//dir/path}:将全部dir 替换为 path:/path1/path2/path3/my.file.txt
示例:
$ strip_all "The Quick Brown Fox" "[aeiou]" #剔除aeiou
Th Qck Brwn Fx
$ strip_all "The Quick Brown Fox" "[[:space:]]" #剔除空格
TheQuickBrownFox
$ strip_all "The Quick Brown Fox" "Quick " #剔除Quick
The Brown Fox
字符串大小写转换
转换成小写
使用${,}替换字符串中的大写字母为小写
string='ABcde'
echo ${string,,} # 输出 abcde
转换成大写
使用${^^}替换字符串中的小写字母为大写
string='ABcde'
echo ${string^^} # 输出 ABCDE
反转字符串大小写
使用${~~}反转字符串中的字母大小写
string='AbCdE'
echo ${string~~} # 输出 aBcDe
进程替换<()
进程替换是把一个进程的输出回馈给另一个进程
-
格式
由圆括号括起的命令
>(command) >>(command) <(command) <<(command)
- 在"<" 或or “>” 与圆括号之间是没有空格的. 如果加了空格将会引起错误信息.
cat <(ls -l) # 等同于 ls -l | cat
sort -k 9 <(ls -l /bin) <(ls -l /usr/bin)
# 列出系统中2个主要的'bin'目录的所有文件,并且按文件名排序.
# 注意是三个明显不同的命令输出回馈给'sort'.
here-string <<<的使用
- 格式
<<< strings
字符串将被扩展并通过标准输入提供给命令
在bash中,引入管道意味着单个命令将在子shell中运行
echo "hello world" | read first second
echo $second $first # 输出为空行
第二个echo命令的输出仅打印一个空格。因为read命令在管道中,所以它在子shell中运行。它从stdin读取2个单词并分配给变量。但是随后命令完成,子shell退出并且变量丢失。
有时,也可以使用花括号解决此问题:
echo "hello world" | {
read first second
echo $second $first
}
但是在脚本的当前shell中仍然没有这些变量。要解决这种情况,就需要使用here-string
read first second <<< "hello world"
echo $second $first
<<的使用
<<
表示此处的文档。
$ cat <<EOF
> hi
> there
> EOF
输出:
hi
there
其中EOF: 可以是任何单词。可以理解为定界符
<
将文件的内容传递到命令的标准输入(输入重定向)
cat < /etc/fstab
/dev/sda2 /boot ext4 nosuid,noexec,nodev,rw,noatime,nodiratime 0 2
/dev/sda4 / ext4 rw,noatime,nodiratime, 0 1
/dev/sdb5 /var ext4 nosuid,noexec,nodev,rw,relatime 0 2
...
文件描述符(fd)
文件描述符 | 通道名 | 描述 | 默认连接 | 用途 |
---|---|---|---|---|
0 | stdin | 标准输入 | 键盘 | read only |
1 | stdout | 标准输出 | 终端 | write only |
2 | stderr | 标准错误 | 终端 | write only |
3以上 | filename | 其他文件 | none | read and/or write |
- 操作
命令 | 作用 | 例子 | 说明 |
---|---|---|---|
&1 | 指定文件描述符,可以是任意描述符(此处为1) | echo “test” >1.txt 2>&1 | 将错误输出重定向到标准输出 |
& | 包含所有文件描述符 | echo “test” &>1.txt | 将标准和错误都重定向 |
&- | 关闭文件描述符 | exec 3>&- | 关闭文件描述符fd3 |
- exec操作文件描述符
exec 3>access.log # 定义fd3 输出到 access.log
echo "这是文件描述符fd3" >&3 # 将标准输出重定向到 fd3
exec 3<&-;exec 3>&- # 关闭文件描述符 fd3
- 一旦关闭了文件描述符,就不能在脚本中向它写入任何数据,否则shell会生成错误消息
- echo “hello” >&3 向文件描述符中输入内容只使用 > 不能用 >> ,此时的 > 不会清空文件
- 是否清空文件需要在exec命令关联文件描述符到文件的时候区别使用 > 或 >>
- read -u 命令可以读取指定文件描述符
进程
fork
- fork是linux的系统调用,用来创建子进程(child process)。子进程是父进程(parent process)的一个副本,从父进程那里获得一定的资源分配以及继承父进程的环境。
- 子进程与父进程唯一不同的地方在于pid(process id)。
- 环境变量(传给子进程的变量,遗传性是本地变量和环境变量的根本区别)只能单向从父进程传给子进程。不管子进程的环境变量如何变化,都不会影响父进程的环境变量。
- export会把父进程中的变量向子进程中继承,但是反过来却不行
source(.) 和sh 和exec的区别
sh:父进程会fork一个子进程,shell script在子进程中执行
source:在原进程中执行,不会fork子进程
exec:在原进程中执行,但是同时会终止原进程