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(表示 “假”),常与 ifwhile 等流程控制语句配合使用。

test 命令有两种等价语法形式,需注意括号前后必须有空格

  1. 标准形式:test 条件
  2. 简化形式:[ 条件 ](更常用,本质是 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 字符串相等 字符串 str1str2 完全相同 [ "abc" = "abc" ] && echo "相等"
str1 != str2 字符串不等 字符串 str1str2 不相同 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 "满足条件"

五、核心注意事项

  1. 空格不可省略[test 的别名,必须与后续条件之间加空格,否则会被解析为普通命令(如 [-f file.txt] 会报错)。
  2. 字符串需加引号:变量或字符串含空格时,必须用双引号包裹(如 [ "$name" = "Zhang San" ]),否则会被拆分为多个参数。
  3. 数值与字符串比较区分
    • 数值比较用 -eq-gt 等(如 [ 5 -gt 3 ]);
    • 字符串比较用 =!= 等(如 [ "5" = "3" ]),若用 [ 5 = 3 ] 虽不报错,但本质是字符串比较,不推荐。
  4. 返回值的特殊性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表示失败;

优点:

  1. 代码模块化,调用方便,节省内存
  2. 代码模块化,代码量少,排错简单
  3. 代码模块化,可以改变代码的执行顺序
#语法一
函数名(){
	代码块
	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"|bc
      

      python3 运算

      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

写脚本

  • 案例模仿
  • 照着文档改写
  • 复杂任务,需求分析,需求拆分,编写模块
posted @ 2025-09-02 20:29  落无一  阅读(16)  评论(0)    收藏  举报