shell 基础知识
Shell 脚本
Shell基础
- Shell:是Linux命令解释器;它是用户与系统内核之间的桥梁;
- Shell-Script(脚本):一种解释型语言;也是命令式语言;作用:可以批量执行命令,实现一些自动化任务,例如一键安装脚本,自动发送邮件、短信、微信、钉钉,系统巡检,系统优化脚本等,数据库备份脚本、垃圾清理脚本。
开发环境:
- Linux + Vim + 可选插件
- VSCode + 插件
- 本地安装 :在桌面版虚拟机的浏览器上下载vscode,并按装插件bash ide ,shellcheck,shell-format,code runner
- 远程访问(ssh):在真机电脑上的vscode上安装插件bash ide ,shellcheck,shell-format,code runner,remote-ssh 进行ssh远程连接
Shell基础语法
脚本的运行方式
- bash:在运行脚本时,会启动一个子shell执行脚本中的命令
- source:加载脚本,在当前的父shell中执行
- chmod +x test.sh #./test.sh
- **. test.sh # . 等价与 source **
变量
数据的别名,创建变量时,会在内存中开辟存储空间,将数据存入内存中,将变量名和内存地址绑定;
变量命名规范:
- 不要和命令相同,建议使用大写字母;
- 使用数字、字母、下划线命名,不要一数字开头;
- Shell变量赋值时,“=”的左右不能有空格;
- 蛇形命名法:多个单词中间用下划线连接,例如 my_name ;
- 驼峰命名法:小驼峰 例如:myName 、getAge ;大驼峰 例如:MyName
- MYSQL_PATH
三种引号:
- 单引号:输出的是字符串本身;
- 双引号:当包含
$变量时,会输出变量的值; - 反引号:当引用的是命令时,会以字符串的方式返回命令执行的结果;
变量的分类:
-
普通变量:在shell运行时子shell中生效;
- MY_NAME=“111”
- echo $MY_NAME
-
全局变量:export 变量名
- export MY_NAME=“111”
- echo $MY_NAME
-
系统环境变量:env 查看 PATH、HOME、SHELL、PWD
- export PATH=$PAHT:/usr/local/mysql /bin #临时生效
- vim /etc/profile #永久生效,开机自动执行,全局生效
- vim ~/.bashrc | ~/.profile #让当前用户开机时生效
-
内置变量(特殊变量):
$?,$0,$1~$9,$!,$@,$*,$#-
$?: 上一条命令是否执行成功, 成功显示0,失败显示其他数字1~127 -
$0:执行脚本时获取脚本的名称 -
$1~$9:第一 ~ 第九个参数 -
$@:获取所有的参数 -
$*:获取所有的参数 -
$*与$@区别:- 相同点:都是引用所有参数。
- 不同点:只有在双引号中体现出来。假设在脚本运行时写了三个参数 1、2、3,,则 " * " 等价于 "1 2 3"(传递了一个参数),而 "@" 等价于 "1" "2" "3"(传递了三个参数)。
-
$#:获取参数的数量 -
$!:获取上一个在后台运行的进程的 PID(进程 ID) -
$(命令) 等价于```命令`` ` 获取命令的执行结果
-
-
转义字符
- \n 换行符
- \t 制表符
- \a 响铃符
- \r 回车符,将光标移动到一行的开头
- 颜色转义字符 "\033[颜色代码;样式代码m要显示的文本\033[0m"
-
echo -e “hello\nworld!”
- -e 识别转义字符
- -n 不换行
-
输入、输出
- echo 输出
- read 输入
if判断
- if 判断
- 【】 等价于 test
- 三种书写方式
- test -e /etc/passwd && echo "OK"
- [ -e /etc/passwd ] && echo "OK"
- if [ -e /etc/passwd ];then echo "OK"; fi
# if 语法格式
#If条件判断语句,通常以if开头,fi结尾。也可加入else或者elif进行多条件的判断
# 单分支语句 ---比较大小
if (条件表达式);then
语句1
fi
# 双分支if 语句
if (表达式);then
语句1
else
语句2
fi
# 多支条件语句 ---判断成绩
if (表达式)
then
语句1
elif
then
语句2
elif
then
语句2
else
语句3
fi
Test命令与参数
在 Linux 中,test 命令是条件测试工具,用于判断文件属性、字符串关系、数值大小等,返回值为 0(表示测试结果为 “真”)或非 0(表示 “假”),常与 if、while 等流程控制语句配合使用。
test 命令有两种等价语法形式,需注意括号前后必须有空格:
- 标准形式:
test 条件 - 简化形式:
[ 条件 ](更常用,本质是test命令的别名)
一、文件测试参数(最常用)
用于检测文件 / 目录的存在性、类型、权限、大小、修改时间等,是脚本中判断文件状态的核心参数。
| 参数 | 测试类型 | 描述(当满足以下条件时返回 “真”) | 示例(返回真则输出 “OK”) |
|---|---|---|---|
-e |
文件存在性 | 指定路径的文件 / 目录存在 | test -e /etc/passwd && echo "OK" |
-f |
文件类型 | 指定路径是普通文件(非目录、设备文件等) | [ -f ~/test.txt ] && echo "OK" |
-d |
文件类型 | 指定路径是目录 | test -d /home && echo "OK" |
-b |
文件类型 | 指定路径是块设备文件(如硬盘、U 盘) | [ -b /dev/sda1 ] && echo "OK" |
-c |
文件类型 | 指定路径是字符设备文件(如键盘、终端) | test -c /dev/tty1 && echo "OK" |
-s |
文件大小 | 文件非空(大小 > 0 字节) | [ -s ~/log.txt ] && echo "日志非空" |
-r |
文件权限 | 当前用户对文件有读权限 | test -r /etc/shadow && echo "有读权限" |
-w |
文件权限 | 当前用户对文件有写权限 | [ -w ~/test.txt ] && echo "有写权限" |
-x |
文件权限 | 当前用户对文件有执行权限(脚本 / 可执行程序) | test -x /bin/ls && echo "ls可执行" |
-g |
文件权限 | 文件设置了SGID(组权限继承) | [ -g /usr/bin/passwd ] && echo "有SGID" |
-u |
文件权限 | 文件设置了SUID(用户权限继承,如 passwd) | test -u /usr/bin/passwd && echo "有SUID" |
-k |
文件权限 | 文件设置了Sticky Bit(仅所有者删自己文件) | [ -k /tmp ] && echo "tmp有Sticky Bit" |
-nt |
修改时间 | 文件 A 的修改时间晚于文件 B(Newer Than) | test ~/a.txt -nt ~/b.txt && echo "a更新" |
-ot |
修改时间 | 文件 A 的修改时间早于文件 B(Older Than) | [ ~/a.txt -ot ~/b.txt ] && echo "a较旧" |
二、字符串测试参数
用于比较字符串的相等性、空值、长度等,需注意字符串建议用双引号包裹,避免空格或特殊字符导致解析错误。
| 参数 | 测试类型 | 描述(返回 “真” 的条件) | 示例 |
|---|---|---|---|
str1 = str2 |
字符串相等 | 字符串 str1 与 str2 完全相同 |
[ "abc" = "abc" ] && echo "相等" |
str1 != str2 |
字符串不等 | 字符串 str1 与 str2 不相同 |
test "abc" != "def" && echo "不等" |
-z str |
空字符串 | 字符串 str 的长度为 0(空字符串) |
[ -z "$empty_var" ] && echo "变量为空" |
-n str |
非空字符串 | 字符串 str 的长度 > 0(非空) |
test -n "$name" && echo "变量非空" |
注意:字符串比较的常见误区
- 若变量未定义,
[ $var = "test" ]会解析为[ = "test" ],导致语法错误;用双引号包裹变量可避免:[ "$var" = "test" ]。 =和!=是字符串比较专用,不能用于数值比较(数值需用-eq、-gt等)。
三、数值测试参数
用于比较两个整数的大小关系,仅支持整数,不支持浮点数。
| 参数 | 测试类型 | 描述(返回 “真” 的条件) | 示例 |
|---|---|---|---|
num1 -eq num2 |
数值相等 | 整数 num1 等于 num2(Equal) |
[ 10 -eq 10 ] && echo "相等" |
num1 -ne num2 |
数值不等 | 整数 num1 不等于 num2(Not Equal) |
test 10 -ne 5 && echo "不等" |
num1 -gt num2 |
数值大于 | 整数 num1 大于 num2(Greater Than) |
[ 20 -gt 15 ] && echo "20大" |
num1 -lt num2 |
数值小于 | 整数 num1 小于 num2(Less Than) |
test 5 -lt 8 && echo "5小" |
num1 -ge num2 |
大于等于 | 整数 num1 大于或等于 num2(Greater or Equal) |
[ 10 -ge 10 ] && echo ">=成立" |
num1 -le num2 |
小于等于 | 整数 num1 小于或等于 num2(Less or Equal) |
test 7 -le 9 && echo "<=成立" |
四、逻辑运算参数
用于组合多个测试条件(与、或、非),实现更复杂的判断逻辑。
| 参数 | 逻辑关系 | 描述(结合多个条件) | 示例(返回真则输出 “OK”) |
|---|---|---|---|
! 条件 |
逻辑非(NOT) | 对单个条件取反(真变假,假变真) | [ ! -f ~/test.txt ] && echo "不是普通文件" |
条件1 -a 条件2 |
逻辑与(AND) | 条件 1 且 条件 2 均为真时,结果为真 | test -f ~/a.txt -a -r ~/a.txt && echo "OK" |
条件1 -o 条件2 |
逻辑或(OR) | 条件 1 或 条件 2 有一个为真时,结果为真 | [ -d ~/dir -o -f ~/file ] && echo "OK" |
扩展:更直观的逻辑运算符([[ ]] 与 (( )))
test 命令的简化形式 [ ] 功能有限,实际脚本中更常用 [[ ]](字符串 / 文件测试) 和 (( ))(数值测试),支持更直观的逻辑运算符(&&、||),无需用 -a、-o:
- 逻辑与:
[[ 条件1 && 条件2 ]]或(( 条件1 && 条件2 )) - 逻辑或:
[[ 条件1 || 条件2 ]]或(( 条件1 || 条件2 ))
示例:
# 判断“是普通文件且有读权限”
[[ -f ~/a.txt && -r ~/a.txt ]] && echo "OK"
# 判断“数值a大于10或小于5”
a=12
(( a > 10 || a < 5 )) && echo "满足条件"
五、核心注意事项
- 空格不可省略:
[是test的别名,必须与后续条件之间加空格,否则会被解析为普通命令(如[-f file.txt]会报错)。 - 字符串需加引号:变量或字符串含空格时,必须用双引号包裹(如
[ "$name" = "Zhang San" ]),否则会被拆分为多个参数。 - 数值与字符串比较区分:
- 数值比较用
-eq、-gt等(如[ 5 -gt 3 ]); - 字符串比较用
=、!=等(如[ "5" = "3" ]),若用[ 5 = 3 ]虽不报错,但本质是字符串比较,不推荐。
- 数值比较用
- 返回值的特殊性:
test命令的返回值与 “真 / 假” 相反 —— 返回0表示 “真”,返回非0表示 “假”(符合 Linux 命令 “无错为 0” 的约定)。
六、实际脚本示例
结合 if 语句使用 test 命令,判断文件是否存在并创建:
#!/bin/bash
file_path="~/test.txt"
# 用 [ ] 判断文件是否不存在
if [ ! -f "$file_path" ]; then
echo "文件 $file_path 不存在,正在创建..."
touch "$file_path" # 创建文件
else
echo "文件 $file_path 已存在"
fi
运行脚本后,若 test.txt 不存在则创建,存在则提示已存在,体现了 test 命令在条件判断中的核心作用。
case 条件循环语句 主要做选项
case语法
case $var in 定义变量;var代表是变量名
pattern 1) 模式1;用 | 分割多个模式,相当于or
command1 需要执行的语句
;; 两个分号代表命令结束
pattern 2)
command2
;;
pattern 3)
command3
;;
*) default,不满足以上模式,默认执行*)下面的语句
command4
;;
esac esac表示case语句结束
- 循环
for循环
for variable_name in {list}
do
command
command
…
done
或者
for variable in a b c
do
command
command
done
- 按照范围循环 :{1..10} ,{a..z} ,
- 循环命令的执行结果 :$(命令) ,```命令`` `
while 循环
#while语法
while [ 表达式 ]
do
command...
done
while [ 1 -eq 1 ] 或者 (( 1 > 2 ))
do
command
command
...
done
函数
概念:一个代码段,起个函数名,通过函数名可以重复调用该代码;
可以使用
$1~$9作为位置参数;return 0 :表示执行成功,1~127表示失败;
优点:
- 代码模块化,调用方便,节省内存
- 代码模块化,代码量少,排错简单
- 代码模块化,可以改变代码的执行顺序
#语法一
函数名(){
代码块
return n
}
#语法二
function 函数名() {
代码块
return N
}
#使用的时候直接调用
函数名
运算
-
整数运算
-
expr 支持数字运算
expr 2 + 3 expr 2 - 3 expr 2 \* 3 expr 4 / 2 expr 3 % 2 -
let 支持变量运算和数字运算
let a=2 let a++ let b=a*3 let b=b**2 let b=b%2 echo "a=%a b=$b" -
$(( )) 支持变量运算和数字运算
echo $(( a=a+1)) -
bc 运算
echo "23 * 23"|bcpython3 运算
echo "print(3+2)" |python3
-
-
浮点数运算
-
bc 运算
# scale是设置小数位数 echo "scale=2;3/2"|bc -
python3 运算
echo "print(3/2)" |python3 #获取随机整数 echo "import random;print(random.randint(1,100))" | python3 #获取随机小数 echo "import random;print(random.random())" | python3
-
数组
数组可以让用户一次赋予多个值,需要读取数据时只需通过索引调用就可以方便读出了。
普通数组:只能使用整数作为数组索引(元素的索引)
关联数组:可以使用字符串作为数组索引(元素的索引)
#语法:
数组名称=(元素1 元素2 元素3 ...)
#通过下标修改元素
数组名称【0】="a"
#获取所有元素
echo ${数组名称[*]}
#获取数组元素的个数
echo ${#数组名称[*]}
#获取元素的索引
echo ${!数组名称[@]}
#切片 获取部分元素
echo ${数组名称[@]:1:3}
#遍历数组的所有元素
for i in ${数组名称[*]}
do
echo $i
done
- 命令
- exit 结束(退出)当前的shell
- break 退出循环,继续执行循环下面(外部)的代码
- continue 退出本次循环,继续进行下一次循环
Linux命令,重点三剑客(awk,grep,sed),运算,数据处理,计划任务
cut 切割字符串,获取部分内容
- -d 指定分隔符
- -c 截取某个字符
- -c 4 截取第四个字符
- -c 1-4 截取1到4个字符
- -c 5- 截取第五个字符以后的内容
- -f 显示的列
tr 替换,删除
- -d 删除匹配到的字符
- tr -d '0-9' < 1.txt 删除所有数字 0-9
- 替换
- tr ‘A-Z’ ‘a-z’ < 1.txt 把大写字母替换为小写字母
sort 对文本文件中所有行进行排序
- 默认排序规则是字符编码排序
- -n 按照数字的排序规则进行排序
- -k 指定按某列进行排序
- -u 去重
- -r 降序排序 ,默认是升序排序
uniq 去重
- -d 显示重复的行
- -i 忽略大小写
tee 双向输出,即能在命令行中显示结果,也能把显示结果保存到文件中
- -a 追加,不覆盖原有内容
paste 将多个文件按列队列合并,不改变源文件
- paste 1.txt 2.txt | tee 3.txt 将1和2的文件按列合并,保存进3中
- -d 指定分隔符,默认是 tab
- -s 把原本的列转换成行后显示出来
xargs 将前一个命令的执行结果作为后一个命令的参数
vim 1.txt
https://127.0.0.1/1.txt
https://127.0.0.1/2.txt
https://127.0.0.1/3.txt
https://127.0.0.1/4.txt
https://127.0.0.1/5.txt
https://127.0.0.1/6.txt
#通过xargs+wget 实现批量下载
cat 1.txt | xargs wget
| 管道符 :将前一个的执行结果作为后一个命令的数据源
特殊符号
! 执行历史命令
!! 执行上一条命令
$ 变量中取内容符
+ - * / % 对应数学运算 加 减 乘 除 取余数
& 后台执行
&& 与运算
&> 将标准输出和标准错误输出都重定向到一个文件
; 分号可以在shell中一行执行多个命令,命令之间用分号分割
> 输出重定向,将命令的执行结果保存到一个文件内,会覆盖原文
>> 追加重定向,将内容添加到文件的最后,不覆盖原文
< 输入重定向,读取文件中的内容,交给命令执行
<< 追加输入重定向,将键盘输入的内容交给命令批量执行
\ 转义字符
$(命令) 获取命令的执行结果 等价于 ``
`` 反引号 命令中执行命令
' ' 单引号,脚本中字符串要用单引号引起来,但是不同于双引号的是,单引号不解释变量
" " 双引号,脚本中出现的字符串可以用双引号引起来
通配符
~ 家目录 # cd ~ 代表进入用户家目录
* 星号是shell中的通配符 匹配所有
? 问号是shell中的通配符 匹配除回车以外的一个字符
[list]: 匹配[list]中的任意单个字符
[!list]: 匹配除list中的任意单个字符
{string1,string2,...}: 匹配string1,string2或更多字符串
进程管理
- jobs 查看后台的进程号
- bg 编号 放到后台继续运行
- fg 编号 放到前台运行
sed 行(流)编辑器
sed -i 's/旧/新/g' 文件名
awk
写脚本
- 案例模仿
- 照着文档改写
- 复杂任务,需求分析,需求拆分,编写模块
浙公网安备 33010602011771号