Shell 是一个应用程序,它连接了用户和 Linux 内核,让用户能够更加高效、安全、低成本地使用 Linux 内核。

bash shell 是一种脚本语言。
通过shell命令操作和控制内核,实现控制操作系统。

bash shell

shell脚本

  • 编写脚本
1
2
3
4
5
6
7
8
# 增加.sh后缀为了方便脚本类别识别
touch demo.sh
vim demo.sh
# '#'是注释,不会被shell解释
# '#!' 标记为 当前脚本需要怎样shell解释器执行
#!/bin/bash
# echo 标准输出器后面的内容
echo "Hello shell"
  • 执行shell脚本
1
2
3
4
5
6
# 给脚本文件增加执行权限
chmod +x demo.sh
# 就在当前目录查找demo.sh并执行
# 除此之外,linux会从PATH中查找待执行脚本并执行
./demo.sh
# sh demo.sh
  • 实践
  1. printf格式化输出
1
2
3
4
# 格式化 %占位 最好用双引号将格式化模板包裹
# 参数列表使用空格分隔
# 如果参数数量不一致,后面将使用%后面对应默认数值返回
printf "%d %s\n" 10 "abc"
  1. read命令从输入设备读取内容
1
2
read arg
echo "Hello ${arg}"

变量

1
2
3
4
5
ARG="shell"  # 声明并赋值 =号两边不要存在空格
echo ${ARG}  # 通过${变量}解释变量名

readonly ARG  # readonly将ARG定义为只读变量,不能被修改
unset ARG     # 解绑变量或者理解删除变量
  • 特殊变量
变量 含义
$0 当前脚本的文件名
$n 传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是$1,第二个参数是$2。
$# 传递给脚本或函数的参数个数。
$* 传递给脚本或函数的所有参数。
$@ 传递给脚本或函数的所有参数。被双引号(" “)包含时,与 $* 将输入整个输出,$@还是逐个输出
$? 上个命令的退出状态,或函数的返回值。
$$ 当前Shell进程ID。对于 Shell 脚本,就是这些脚本所在的进程ID。
  • 替换
1
2
3
4
5
# 命令替换
# 反引号包裹shell命令集合,会将这个执行结果存储于临时变量
DATE=`date`
echo ${DATE}
# Sun Jun 26 21:12:04 CST 2022

变量替换

形式 说明
${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 的值。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
DATE=`date`
echo ${DATE:+'arg'}
# arg
echo ${DATE}
# Sun Jun 26 21:25:03 CST 2022
unset DATE
echo ${DATE:?NONE}
# -bash: DATE: NONE
echo ${DATE:-arg}
# arg
echo ${DATE:=$(date)}
# Sun Jun 26 21:29:33 CST 2022
echo ${DATE}
# Sun Jun 26 21:29:33 CST 2022

运算符

  • 算术运算:expr 指定并执行表达式
1
2
3
4
5
6
# arg=`2 + 2` --> bash不支持
# expr 2+2 --> 2+2
expr 2 + 2
# 4
arg=`expr 2 \* 2`
echo ${arg}
  • 关系运算
运算符 说明
-eq 检测两个数是否相等,相等返回 true。同算数运算符==
-ne 检测两个数是否相等,不相等返回 true
-gt 检测左边的数是否大于右边的,如果是,则返回 true。
-lt 检测左边的数是否小于右边的,如果是,则返回 true。
-ge 检测左边的数是否大等于右边的,如果是,则返回 true。
-le 检测左边的数是否小于等于右边的,如果是,则返回 true。
1
2
3
4
5
6
7
8
#!/bin/bash
a=10;b=20
# [[ ${a} -ne ${b} ]]; 注意空格
if [[ ${a} -ne ${b} ]]; then
    echo "${a} not qual to ${b}"
else
    echo "${a} qual to ${b}"
fi
  • 布尔运算符
运算符 说明
! 非运算,表达式为 true 则返回 false,否则返回 true。
-o 或运算(or),有一个表达式为 true 则返回 true。
-a 与运算(and),两个表达式都为 true 才返回 true。
  • 字符串运算符
运算符 说明举例
= 检测两个字符串是否相等,相等返回 true。 [ $a = $b ] 返回 false。
!= 检测两个字符串是否相等,不相等返回 true。[ $a != $b ] 返回 true。
-z 检测字符串长度是否为0,为0返回 true。 [ -z $a ] 返回 false。
-n 检测字符串长度是否为0,不为0返回 true。 [ -n $a ] 返回 true。
str 检测字符串是否为空,不为空返回 true。 [ $a ] 返回 true。
  • 文件操作符
操作符 说明举例
-b file 检测文件是否是块设备文件,如果是,则返回 true。 [ -b $file ] 返回 false。
-c file 检测文件是否是字符设备文件,如果是,则返回 true。 [ -c $file ] 返回 false。
-d file 检测文件是否是目录,如果是,则返回 true。 [ -d $file ] 返回 false。
-f file 检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。 [ -f $file ] 返回 true。
-g file 检测文件是否设置了 SGID 位,如果是,则返回 true。 [ -g $file ] 返回 false。
-k file 检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。 [ -k $file ] 返回 false。
-p file 检测文件是否是具名管道,如果是,则返回 true。 [ -p $file ] 返回 false。
-u file 检测文件是否设置了 SUID 位,如果是,则返回 true。 [ -u $file ] 返回 false。
-r file 检测文件是否可读,如果是,则返回 true。 [ -r $file ] 返回 true。
-w file 检测文件是否可写,如果是,则返回 true。 [ -w $file ] 返回 true。
-x file 检测文件是否可执行,如果是,则返回 true。 [ -x $file ] 返回 true。
-s file 检测文件是否为空(文件大小是否大于0),不为空返回 true。 [ -s $file ] 返回 true。
-e file 检测文件(包括目录)是否存在,如果是,则返回 true。 [ -e $file ] 返回 true。

字符串和数组

  • 字符串

““和’‘的区别在于’‘原始输出 ““进行转义等操作

1
2
3
4
5
6
7
8
# 字符串长处
str='Bash Shell Script'
echo ${#str}
# 字符串切片
echo ${str:1}  # ash Shell Script
echo ${str:1:4}  # ash
echo ${str:0}  #  Bash Shell Script
echo ${str:-1}  #  Bash Shell Script
  • 数组
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
array=(1, 2, 3, "shell")
echo ${arry}
echo ${array[2]} #读取下标为2的元素
echo ${array[*]} #读取所有元素
echo ${array[@]} #读取所有元素


echo ${#arrae[*]} #获取数组长度
echo ${#arrae[@]} #获取数组长度
echo ${#arrae[1]} #获取数组中单个元素的长度

控制

  • if then--elif then--else--fi
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#!/bin/bash
a=10;b=20
# [[ ${a} -ne ${b} ]]; 注意空格
if [[ ${a} -gt ${b} ]]; then
    echo "${a} great to ${b}"
elif [[ ${a} -lt ${b} ]]; then
    echo "${a} less to ${b}"
else
    echo "${a} equal to ${b}"
fi
  • case in ... esac
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#!/bin/bash
grade="B"

case ${grade} in   # in 不能少
    "A") echo "great";;  # case的匹配方式 ;; 结束匹配
    "B") echo "good";;
    "C") echo "gerular";;
    *) echo "Sorry"; echo "fighting";; # 其余或者理解为default
    # ?) echo "Sorry"; echo "fighting";; # 其余或者理解为default
esac
  • for in do ... done
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/bin/bash

# 遍历字符串
for ch in 'This a test'; do
    echo ${ch}
done

# 遍历数组
for num in 1 2 3 4; do
    echo ${num}
done

# 遍历当前目录
for f in *; do
    echo ${f}
done

# 遍历文件内容
fc=`cat test.log`
for fc_q in ${fc}; do
    echo ${fc_q}
done
  • while ; do ... done
1
2
3
4
5
6
7
#!/bin/bash

c=0;
while [[ ${c} -lt 3 ]]; do
    echo "Curr Val is ${c}"
    c=`expr ${c} + 1`
done
  • until ;do ... done 直到满足until后的条件推出循环
1
2
3
4
5
6
7
#!/bin/bash

c=0;
until [[ ${c} -eq 3 ]]; do
    echo "Curr Val is ${c}"
    c=`expr ${c} + 1`
done
  • break continue

函数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#!/bin/bash

# 定义函数
function hello() {
    echo "Hello Shell"; ## 如果是指出return 最后一句将作为返回值返回
    return ; ## 返回值只能是整数,0标识成功,其他至标识失败
}

# 调用函数,不用加()
hello
  • 传递
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#!/bin/bash

## 获取参数是在函数内部获取,在调用函数传入
function sum() {
    case $# in  ## 获取入参格式
        0) echo "No param";;
        1) echo $1;;
        2) echo `expr $1 + $2`;;
        *) echo "$# params!It's too much!";;
    esac
}

sum 1;
sum 1 2;
sum 1 2 3;

# 获取函数返回值
s=$(sum 1 2)
echo "func resturn ${s}"

数据流

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#!/usr/bin/bash

# 输出重定向
touch test.log
which bash > test.log
who > test.log  # 覆盖which bash数据作为新的数据内容
which bash >> test.log  # 追加至原有数据的后面

# 输入重定向
# cat test.log <--> cat < test.log 等价
wc -l < test.log

# command 2 > file  将stderr重定向至file
# command 2 >> file  将stderr追加至file
# command > file 2>&1  stdout 和 stderr 合并后重定向到 fil
# command < file >file2 stdin 和 stdout 都重定向

# /dev/null 最为垃圾站的使用

重定向

命令 说明
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 之间的内容作为输入。

其他文本处理工具

  • awk
  • sed