Shell进修

一、Shell初步了解

1.shell是什么

Shell 就是操作系统内核和用户之间的 “翻译官”。

用户敲键盘输入命令,shell 把命令翻译给系统内核,内核执行完再把结果通过 shell 展示给用户。

操作系统结构:

1
用户 → Shell → 内核(Kernel)→ 硬件(CPU、硬盘、内存)

2.shell(程序)和shell脚本(.sh)

Shell(程序):打开 Git Bash、Linux 终端,这个运行程序本身就是 bash 程序,用来逐条执行命令。

Shell 脚本(.sh 文件):把一长串命令写到文本文件里,批量自动执行,这个文件就叫 shell 脚本。

总结:手动一条条敲命令:直接在 shell 程序里交互执行;把命令写成文件批量运行:执行 shell 脚本。

3.常见的 Shell 种类

bash(Bourne Again Shell):最主流,Linux、Git Bash 默认都是它。

脚本开头常常会有 #!/bin/bash ,这段就是指定用bash这个解释器。

1
2
3
4
5
6
7
8
#运行该脚本时,调用 bash 这个 shell 程序 来解析执行文件里的代码。
#!/bin/bash

#------------------
#
# shell命令
#
#------------------

二、Shell运行

shell脚本常在Linux环境下运行,如果有一个名为demo.sh的shell脚本文件,运行方式为在终端控制台输入 ./demo.sh,即可运行。

1
2
3
4
5
# 直接运行脚本
./demo.sh

# 脚本需要输入参数
./demo sh 参数1 参数2 参数3 (依次类推)

这里有两个问题注意点:

(1)权限问题:Linux 严格区分可读、可写、可执行三种权限。

而普通文本文件默认只有读写权限,没有执行权限。因此写好的 demo.sh,系统默认把它当成普通文档,拒绝把它当成程序运行。所以必须手动加上 x(执行权限),才能用 ./demo.sh 启动脚本。不加执行权限,Linux 会不让直接运行当前的脚本文件。

权限添加方式一般采用下面两种:

1
2
3
4
5
6
# 只给所有人加上【执行权限】,读写权限保持原样,安全。
chmod a+x demo.sh
# 把读、写、执行全部放开给所有人,权限拉满,仅本地临时测试用,风险极高。
chmod 777 demo.sh
# 所有者可读写执行,其他人只能读和运行,不能修改,较为稳妥的生产权限。
chmod 755 demo.sh

这里补充一个数字权限对照表:

数字 权限
4 读 r
2 写 w
1 执行 x

7=4+2+1=rwx,777=rwxrwxrwx。

(2)Windows运行问题:

首先,在原生Windows(双击文件、CMD)下,Windows 靠文件后缀名识别程序:.exe.bat.cmd,而且Windows 没有 Linux 这套 rwx 权限机制,完全不需要 chmod。相应的,shell 脚本在纯 Windows 下也不能直接运行。因此常使用Git Bash、WSL等模拟 Linux 环境,同时也会模拟 Linux 文件权限,这时就要按照Linux的方式添加文件权限。

最后补充两个不需要添加权限,也能运行脚本的写法:

1
2
3
4
#  bash 解释读取文件
bash demo.sh
# sh 解释器运行
sh demo.sh

这里是启动 sh/bash 程序,让它去读取这个文本文件,把里面的命令逐条执行。此时 demo.sh 只是一个普通文本,只需要可读权限,有没有 x(执行权限)无所谓。而./demo.sh直接把 demo.sh 当作可执行程序运行。这种情况下,文件必须拥有执行权限,否则会报权限错误。

三、常用基础命令

1.echo 打印输出
1
2
echo hello
echo "hello world"
2.read 接收键盘输入
1
read 变量名
3.变量赋值(等号两边不能有空格)
1
var=100
4.算术运算
1
$((1+2))
5.判断符号(中括号前后必须空格)
1
2
3
4
5
6
[ 条件 ]
-f 文件是否存在
-gt 大于
-lt 小于
-ge 大于等于
-le 小于等于
6.重定向符号
1
2
3
> 覆盖写入文件
>> 追加写入文件
< 文件作为程序输入
7.注释规则
1
2
3
4
5
# 单行注释
: '
多行注释
内容
'

四、基础语法完整版脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#!/bin/bash
# 一、输出命令 echo
echo "===== 基础指令演示 ====="
echo 普通文字
echo "带空格的字符串"
echo -n "不换行输出"

# 二、变量
name="张三"
age=22
echo "姓名:$name,年龄:$age"

# 三、位置参数(命令行传入参数)
echo "第一个参数:$1"
echo "第二个参数:$2"
echo "总参数个数:$#"

# 四、读取键盘输入 read
echo "请输入一句话:"
read msg
echo "你输入的内容:$msg"

# 五、数值运算
a=10
b=5
c=$((a + b))
d=$((a - b))
echo "a+b=$c"
echo "a-b=$d"

# 六、if 判断
if [ $age -ge 18 ]
then
echo "成年人"
else
echo "未成年人"
fi

# 七、for 循环
echo "循环输出:"
for num in 1 2 3 4
do
echo $num
done

# 八、while 循环
i=1
while [ $i -le 3 ]
do
echo "i=$i"
i=$((i+1))
done

# 九、文件判断
if [ -f "base.sh" ]
then
echo "脚本文件存在"
fi

# 十、重定向 > 输出到文件
echo "内容写入文件" > test.txt

五、核心高频符号

1.$ dollar符(触发变量解析、命令替换、算术运算)

(1)位置参数(脚本传入参数)
变量 说明
$0 当前脚本的文件名
$1 $2 ... $9 第 1~9 个命令行参数
${10} 第 10 个参数,必须加大括号
$# 命令行参数总个数
$* 所有参数,合并成一整个字符串,IFS 分隔
$@ 所有参数,保留每一项独立,带空格参数不会拆分
(2)进程与执行状态变量
变量 含义
$$ 当前 shell 进程 PID
$PPID 父进程 PID
$? 上一条命令退出码:0 成功,非 0 失败
$! 最近一个后台进程(&)的 PID
$- 当前 shell 的选项标志
(3)Shell 环境内置变量
变量 作用
$HOME 当前用户家目录
$PWD 当前工作目录
$OLDPWD 上一次所在目录
$PATH 可执行程序搜索路径
$USER 当前用户名
$UID 当前用户 ID
$SHELL 当前使用的 shell
$RANDOM 随机整数 (0~32767)
$LINENO 当前脚本行号
(4)$ 开头语法结构
写法 用途
${var} 变量取值,划定变量边界
${var:-默认值} 变量为空则使用默认值
${var:=默认值} 变量为空就赋值 + 使用默认值
${var:?报错信息} 变量为空直接抛出错误退出
${var:+替代值} 变量有值才用替代值
${var:起始:长度} 字符串截取
$(command) 执行命令,捕获输出(推荐代替反引号)
$((算术表达式)) 整数四则运算
$[算术式] 简化算术运算(bash 兼容,不推荐移植)
(5)特殊符号对 $ 的影响
1
2
3
4
5
6
7
8
9
10
# 单引号 '$var' 原样输出字符串 $var,不解析变量
# 双引号 "$var" 解析变量,保留字符串内部空格
# ===================================================================
# 双引号举例
# 变量内部包含2个连续空格 str1="hello world shell"
# 变量内部包含2个连续空格 str2="hello world shell"
# 双引号引用变量,保留原有空格 echo "$str" 输出 hello world shell
# 无双引号引用变量,连续空格合并成单个空格 echo $str 输出 hello world shell
# ===================================================================
# 反斜杠 \$ 转义,输出字符 $

2.* 星号(通配符 + 正则 + 运算)

写法 用途
*.txt 文件名通配,匹配所有 txt 文件
$((2*3)) 算术乘法
* 正则,代任意字符
"$*" 把所有位置参数合并成一个字符串
${arr[*]} 数组,把数组所有元素合并为一整个字符串

3.# 井号

写法 用途
# 这是注释 注释
$# 统计参数个数
${str#前缀} 字符串截断,删掉最短前缀
${str##前缀} 字符串截断,删掉最长前缀

4.? 问号

写法 用途
file.? 通配符,匹配任意单个字符,比如可以匹配file.a
[ $? -eq 0 ] && echo OK || echo FAIL 退出状态三元判断
${var:?错误信息} 变量容错
s? 正则,匹配 0 或 1 个字符(匹配字符 s,出现 0 次或 1 次)

5.[] 方括号

写法 用途
[ -f file ] 测试判断,条件测试
arr[0] 数组下标
[参数1-参数2] 文件名通配,[0-9] 匹配一位数字,[a-z] 匹配小写字母
[abc] 正则字符集,匹配abc中任意一个,单独匹配,匹配一次
$[1+1] 算术运算

六、双符号组合

写法 用途
${} 变量处理
$() 命令替换
$(( )) 数学运算
&& || 逻辑判断
>> << > < 重定向
## %% # % 字符串修剪