Shell脚本基础语法教程

目录

  • 前言
  • 一、Shell变量
    • (一)定义
    • (二)变量定义规则
    • (三)变量的定义方式
      • 1. 基本方式
      • 2. 命令结果赋值给变量
      • 3. 交互式定义变量
      • 4. 定义有类型的变量
    • (四)变量的分类
      • 1、本地变量
      • 2、环境变量
      • 3、全局变量
      • 4、系统变量
  • 二、四则运算
    • (一)、四则运算符
    • (二)、i++和++i
  • 三、条件判断
    • (一)、语法格式
    • (二)条件判断相关参数
      • 1、判断文件类型
      • 2、判断文件权限
      • 3、判断文件新旧【文件的修改时间】
      • 4、判断整数 ==常用==
      • 5、判断字符串 ==常用==
      • 6、多重判断
  • 四、if语句
    • (一)if结构:fi结束标志
    • (二)、if...else结构
    • (三)、if ... elif ...else结构
    • (四)、层层嵌套结构
  • 五、循环语句
    • (一)、for循环
      • 1、语法结构
        • 1)、列表循环
        • 2)、不带列表循环
        • 3)、类C风格
    • (二)、while语句
      • 1、语法结构
    • (三)、until语句
      • 1、语法结构
  • 六、正则表达式
    • (一)第一类正则
      • 1、==常用==
      • 2、其他常用元字符
      • 3、扩展类正则常用元字符
    • (二)第二类正则
  • 七、sed命令
    • (一)介绍
    • (二)使用方法
      • 1、命令行格式
      • 2、脚本模式
  • 八、awk命令
    • (一)概述
      • 1、概述
      • 2、awk能干什么?
    • (二)使用
      • 1、命令行模式
      • 2、脚本模式
    • (三)内部相关变量
      • 1、常用内置变量
    • (四)工作原理
    • (五)进阶
      • 1. 格式化输出print和printf
      • 2. awk变量定义
      • 3. awk中BEGIN...END使用
      • 4. awk的脚本编程
        • (一)if结构
        • (二)if...else结构
        • (三)if...elif...else结构
  • 十、export命令
    • (一)什么是export命令?
    • (二)为什么要用export命令?
    • (三)怎么使用export命令
      • 1、解释
      • 2、语法
      • 3、参数说明
      • 3、 结论
  • 参考资料


前言

  本文简单记录了Shell脚本的相关知识。预计阅读时间10分钟+。


一、Shell变量

(一)定义

  • 变量名=变量值

    A=hello  # 定义变量A,其值是hello
    echo $A  # 调用变量,注意要给钱的,“$”
    
    注意:
    	调用其他的形式:
    		1. ${} 
    
  • 取消变量:unset A

(二)变量定义规则

  • 区分大小写,一般大写
  • 不能有特殊符号
  • 变量值有空格要用单双引号
  • 变量名字不可以用数字开头
  • 等号两边不能有任何空格,如 A = 3 错的

(三)变量的定义方式

1. 基本方式

变量名=变量值

A=1546
echo $A
输出:
1546

2. 命令结果赋值给变量

``(反撇号)或$()

A=`hostname`
echo $A
输出:
algo-System-Product-Name

B=`data +%F`
echo ${B}
输出:
2021-12-27

3. 交互式定义变量

read [选项] 变量名

选项 功能
-p 定义提示用户的信息
-n 定义字符数(限制输入长度)
-s 不显示(用户输入的内容)
-t 定义超时时间
用法1:用户自己定义变量值
read name
harry
echo $name
harry
read -p "Input your name:" name
Input your name:tom
echo $name
tom

用法2:变量值来自文件
cat 1.txt 
10.1.1.1 255.255.255.0
read ip mask < 1.txt 
echo $ip
10.1.1.1
echo $mask
255.255.255.0

4. 定义有类型的变量

declare [选项] 变量名=变量值

选项 功能
-i 将变量看成整数
-r 定义只读变量
-a 定义普通数组,查看普通数组
-A 定义关联数组;查看关联数组
-x 将变量通过环境导出

(四)变量的分类

1、本地变量

	-  当前用户自定义的变量,==当前进程有效,其他进程或子进程无效==

2、环境变量

-  当前进程有效,子进程也可以用 
-  env:查看当前用户环境变量
  • set:查看本地变量、环境变量
  • export:变量名=变量值,将本地变量改成环境变量

3、全局变量

-  所有用户生效,/env/bashrc 

4、系统变量

- shell本身已经固定好了它的名字和作用
内置变量 含义
$? 上一条命令执行后返回的状态;状态值为0表示执行正常,非0表示执行异常或错误
$0 当前执行的程序或脚本名
$# 脚本后面接的参数的个数
$* 脚本后面所有参数,参数当成一个整体输出,每一个变量参数之间以空格隔开
$@ 脚本后面所有参数,参数是独立的,也是全部输出
$1-$9 脚本后面的位置参数,$1表示第1个位置参数,依次类推
${10}-${n} 扩展位置参数,第10个位置变量必须用{}大括号括起来(2位数字以上扩起来)
$$ 当前所在进程的进程号,如echo $$
$! 后台运行的最后一个进程号(当前终端)
!$ 调用最后一条命令历史中的参数

二、四则运算

  • 算术运算:默认情况,shell只能支持简单的整数运算
  • 运算内容:+、-、*、/、%(求余)

(一)、四则运算符

expr 记得加空格如:expr 10 - 5,乘号需要转义 【实际操作貌似不用了,我的没有转义也可以使用

表达式 举例
$(()) echo $((1+1)) 输出2
$[] echo $[10-5] 输出5
expr expr 10 / 5 注意空格
let n=1;let n+=1 等价于 let n=n+1

(二)、i++和++i

-  对于变量没什么影响 
  • 对表达式的值有影响:
    • i++:先赋值,再运算
    • ++i:先运算,再赋值

三、条件判断

(一)、语法格式

	- 格式1:test 条件表达式
	- 格式2: [ 条件表达式 ]
	- 格式3:[[ 条件表达式 ]] ,支持正则 =~

注意:

- 格式2和格式3,[空格+表达式+空格],两边都有空格哦

(二)条件判断相关参数

1、判断文件类型

判断参数 含义
-e 判断文件是否存在(任何类型文件)
-f 判断文件是否存在并是一个普通文件
-d 判断文件是否存在并且是一个目录
-L 判断文件是否存在并且是一个软连接文件
-b 判断文件是否存在并且是一个块设备文件
-S 判断文件是否存在并且是一个套接字文件
-c 判断文件是否存在并且是一个字符设备文件
-p 判断文件是否存在并且是一个命名管道软件
-s 判断文件是否存在并且是一个非空文件(有内容)

2、判断文件权限

判断参数 含义
-r 当前用户对其是否可读
-w 当前用户对其是否可写
-x 当前用户对其是否可执行
-u 是否有suid,高级权限冒险位
-g 是否sgid,高级权限强制位
-k 是否有t位,高级权限粘滞位

3、判断文件新旧【文件的修改时间】

判断参数 含义
file1 -nt file2 比较file1是否比file2新
file1 -ot file2 比较file1是否比file2旧
file1 -ef file2 比较是否为同一个文件,或者用于判断硬链接,是否指向同一个inode

4、判断整数 常用

参数 含义
-eq 相等
-ne 不等
-gt 大于
-lt 小于
-ge 大于等于
-le 小于等于

5、判断字符串 常用

判断参数 含义
-z 判断是否为空字符串,字符串长度为0成立
-n 判断是否为非空字符串,字符串长度为0成立
string1 = string2 判断字符串是否相等
string1 != string2 判断字符串是否不相等

6、多重判断

逻辑运算符,从左往右看

符号 含义
-a 和 && 逻辑与
-o 和 | | 逻辑或

特别说明:

- &&   前面的表达式==为真==,才会执行后面的代码 
- | |     前面的表达式==为假==,才会执行后面的代码
- ;     ==只==用于==分割==命令或表达式

四、if语句

(一)if结构:fi结束标志

if [ condition ];then
	command
	command
fi
或
[ 条件 ] && command

(二)、if…else结构

​ 分岔路口,二选一

if [ condition ];then
	command
else
	command
fi
或
[ 条件 ] && command1 || command2

(三)、if … elif …else结构

选择很多,能走的只有一条

if [ condition1 ];then
	command1
elif[ condition2 ];then
	command2
else
	command3
fi

(四)、层层嵌套结构

if [ condition1 ];then
	command1
	if [ condition2 ];then
		command2
else
	if [ condition3 ];then  
		command3
	elif [ condition4 ];then
		command4
	else
		command5
fi

五、循环语句

(一)、for循环

使用场合:循环次数已知

1、语法结构

1)、列表循环

for variable in {list}
	do 
		command
		command
		...
	done
或者
for variable in a b c
		do 
		command
		...
	done

2)、不带列表循环

		- 循环次数用户指定
for variable
	do 
		command
		command
		...
	done

3)、类C风格

for ((expr1;expr2;expr3))
	do 
		command
		command
		...
	done
expr1:定义变量并赋初值
expr2:决定是否进行循环(条件)
expr3:决定循环变量如何改变,决定循环什么时候退出
for(( i=1;i<=5;i++))
	do
		echo $i
	done

(二)、while语句

1、语法结构

# 普通方式
定义变量; while[ 表达式 ];do 程序;let i++;done
# 类C风格
定义变量;while((表达式));do 程序;let i++;done

(三)、until语句

条件进入循环,退出循环

1、语法结构

until expression [ 1 -ed -1] (( 1 >= 1))
	do 
		command
		...
	done

六、正则表达式

(一)第一类正则

  • Regular Expression、regex或regeexp,缩写为RE)

  • 元字符:如:点.、星*、问号?等。

  • 前导字符:位于元字符前的字符

1、常用

符号 解释 案例
. 匹配除了换行符以外的任意单个字符
* 前导字符出现0次或连续多次
.* 任意长度字符 ab.*
^ 行首(以…开头) ^root
$ 行尾(以…结尾) bash$
^$ 空行
[] 匹配括号里任意单个字符或一组单个字符 [abc]
[^] 匹配不包含括号里任意单个或一组单个字符 [^abc]
^[] 匹配以括号里任意单个字符或一组单个字符开头 ^[abc]
^[ ^ ] 匹配不以括号里任意单个字符或一组单个字符开头 ^[ ^abc ]

2、其他常用元字符

符号 解释 案例
< 取单词的头
> 取单词的尾
< > 精确匹配
{n} 匹配前导字符连续出现n次
{n, } 匹配前导字符至少出现n次
{n, m} 匹配前导字符出现n次与m次之间
( ) 保存被匹配的字符
\d 匹配数字(grep -P) [0-9]
\w 匹配字符数字下划线(grep -P) [a-zA-Z0-9_]
\s 匹配空格、制表符、换页符(grep -P) [\t\r\n]

3、扩展类正则常用元字符

  • grep 要用 必须加 -E,或者用egrep
  • sed要用必须加-r
符号 解释 案例
+ 匹配一个或多个前导字符
匹配零个或一个前导字符
|
() 组字符(看成整体)
{n} 前导字符重复n次
{n,} 前导字符重复至少n次
{n,m} 前导字符重复n到m次

(二)第二类正则

表达式 功能
[:alnum:] 字母与数字字符
[:alpha:] 字母字符(包括大小写)
[:blank:] 空格与制表符
[:digit:] 数字
[:lower:] 小写字母
[:upper:] 大写字母
[:punct:] 标点符号
[:space:] 包含换行符,回车等在内的所有空白

七、sed命令

(一)介绍

  • sed是一行一行读取文件内容并按照要求进行处理,把处理后的结果输出到屏幕
  • 不会直接修改源文件

(二)使用方法

1、命令行格式

sed [选项] ‘处理动作’ 文件名

常见选项

选项 含义
-e 进行多项(多次)编辑
-n 取消默认输出
-r 使用扩展正则表达式
-i 原地编辑(修改文件
-f 指定sed脚本文件名

常见动作

注意:所有动作都在单引号里

动作 含义
‘p’ 打印
‘i’ 在指定行之前插入内容
‘a’ 在指定行之后插入内容
‘c’ 替换指定行所有内容
‘d’ 删除指定行

对文件进行搜索替换

- sed [选项] `'s/搜索内容/替换内容/动作'` 需要处理的文件
- p打印;全局替换g
命令 解释
r 从另外文件中读取内容
w 内容另存为
& 保存查找串以便在替换串中引用
= 打印行号
! 对所选行以外的所有行应用命令,放到行数之后
q 退出

2、脚本模式

  • sed -f sacripts.sh file
  • 脚本第一行:#!/bin/sed -f

注意事项

脚本文件只一个sed命令行清单。'commands'
在每行的末尾不能有任何空格、制表符(tab)或其他文本。
如果在一行中有多个命令,应用分号分割。
不需要且不可用引号保护命令
#号开头的行为注释

八、awk命令

(一)概述

1、概述

  • 编程语言,对文本和数据进行处理
  • 逐行扫描文件,寻找匹配的特定模式的行
  • gawk是awk的GUN版本

2、awk能干什么?

  • awk用来处理文件和数据的,
  • 可以用来统计数据,比如网站的访问量,访问的IP
  • 支持条件判断,支持for和while循环

(二)使用

1、命令行模式

  • 语法结构:

    awk 选项 '命令部分' 文件名
    特别说明:
    	引用shell变量需要用==双引号引起==
    
  • 常用选项介绍

    命令 功能
    -F 定义字符按分割符号,默认的分隔符是空格
    -v 定义变量并赋值
  • 命名部分说明

    • 正则表达式,地址定位

      '/root/{awk语句}'   sed中:'/root/p'
      
    • {awk语句1;awk语句2;…}

      '{print $0; print $1}'   sed中:'p'
      
    • BEGIN…END…

      'BEGIN{awk语句};{处理中};END{awk语句}'
      'BEGIN{awk语句};{处理中}'
      '{处理中};END{awk语句}'
      

2、脚本模式

  • 脚本编写

    #!/bin/awk -f   # 定义魔法字符
    以下是awk引号里的命令清单,不要用引号保护命令,多个命令用分号间隔
    BEGIN{FS=":"}
    NR==1,NR==3{print $1"\t"$NF}
    
  • 脚本执行

    方法1:
    awk 选项 -f awk的脚本文件 要处理的文本文件
    awk -f awk.sh filename
    方法2:
    ./awk的脚本文件(或绝对路径) 要处理的文本文件
    ./awk.sh filename
    

(三)内部相关变量

1、常用内置变量

变量 变量说明 备注
$0 当前处理行的所有记录
$1,$2,$3…$n 文件中每行以间符号分割的不同字段 awk -F: ‘{print $1,$3}’ 1.txt
NF 当前记录的字段数(列数) awk -F: ‘{print NF}’ 1.txt
$NF 最后一列 $(NF-1)表示倒数第二行
FNR/NR 行号
FS 定义间隔符 ‘BEGIN{FS=":"};{print $1,$3}’
OFS 定义输出字段分隔符,默认空格
RS 输入记录分隔符,默认换行
ORS 输出记录分隔符,默认换行
FILENAME 当前输入的文件名

(四)工作原理

awk -F: '{print $1,$3}' /etc/passwd
  1. awk使用一行作为输入,并经这一行赋给内部变量$0,每一行可称为一个记录,以换行符(RS)结束;

  2. 每行被间隔符:(默认为空格或制表符)分解成字段(或域),每个字段存储在已编号的变量中,从$1开始;

    问:awk如何知道用空格来分割字段呢?
    答:因为有一个内部变量FS来确定字符段分隔符。初始时,FS赋为空格

  3. awk使用print函数打印字段,打印出来的字段会以空格分隔,因为1,3之间有一个逗号。都好比较特殊,它映射为另一个内部变量,称为输出字段分隔符OFS,OFS默认为空格;

  4. awk处理完一行后,将从文件中获取另一行,并将其存储在$0中,覆盖原来的内容,然后将新的字符串分割成字段并进行处理。该过程将持续到所有行处理完毕。

(五)进阶

1. 格式化输出print和printf

print函数     类似echo
# data | awk '{print "Month: "$2"\nYear: "$NF}'
# awk -F: '{print "username is: " $1 "\t uid is: "$3}' /etc/passwd
printf 函数     类似echo -n 
# awk -F: '{print "%-15s %-10s %-15s\n", $1, $2, $3}' /etc/passwd
# awk -F: '{print "|%15s| %10s| %15s|\n", $1, $2, $3}' /etc/passwd
# awk -F: '{print "|%-15s| %-10s| %-15s|\n", $1, $2, $3}' /etc/passwd

%s 字符类型
%d 数值类型
- 表示左对齐,默认是右对齐
printf默认不会再行尾自动换行,加 \n

2. awk变量定义

# awk -v NUM=3 -F: '{print $NUM}' /etc/passwd  【注意】
# awk -v NUM=3 -F: '{print NUM}' /etc/passwd
# awk -v num=1 'BEGIN{print num}'
1
# awk -v num=1 'BEGIN{print $num}'    【注意】

注意:
	awk中调用定义的变量不需要加$

3. awk中BEGIN…END使用

  • BEGIN:表示程序开始前执行
  • END:表示所有文件处理后执行
  • 用法:'BEGIN{开始处理之前};{处理中};END{处理结束后}'

4. awk的脚本编程

(一)if结构

格式:
awk 选项 '正则,地址定位{awk语句}' 文件名
{if(表达式){语句1;语句2;...}}

案例:
# awk -F: '{if($3>=500 && $3<=60000) {print $1,$3}}' passwd

# awk 'BEGIN{if($(id -u)==0){print "admin"}}'
admin

(二)if…else结构

格式:
{if(表达式){语句;语句;...}} else {语句;语句;...}}
awk -F: '{if($3>=500 && $3<=60000) {print $1"是普通用户"} else {print $1"不是普通用户"}}' passwd

awk 'BEGIN{if($(id -u)>=500 && $(id -u) !=65534) {print "是普通用户"} else {print "不是普通用户"}}'

(三)if…elif…else结构

格式:
{if(表达式1) {语句;语句;...} elif(表达式2) {语句;语句;...} elif(表示3) {语句;语句;...} else {语句;语句;...}}

awk -F: '{if($3==0) {print $1"是普通用户"} elif($3>=1 && $3<=499) {print $1"不是普通用户"}}' passwd

十、export命令

(一)什么是export命令?

  • 在子 shell中定义的变量只在该子shell内有效。如果在一个shell脚本程序中定义了一个变量,当该脚本程序运行时,这个定义的变量只是该脚本程序内 的一个局部变量,其他的shell不能引用它,要使某个变量的值可以在其他shell中被改变,可以使用export命令对已定义的变量进行输出。 export命令将使系统在创建每一个新的shell时定义这个变量的一个拷贝。

(二)为什么要用export命令?

  • 为了使我们定义一个变量时可以在子shell中被调用,而不需要重复去定义

(三)怎么使用export命令

1、解释

1、 Linux export命令用于设置或显示环境变量。
2、在shell中执行程序时,shell会提供一组环境变量。export可新增,修改或删除环境变量,供后续执行的程序使用。export的效力仅及于该次登陆操作。

2、语法

  • export [选项] 变量名=变量值

3、参数说明

选项 解释
-f 代表 [变量名称] 中为函数名称
-n 删除指定的变量,注:变量实际未删除,知识不会输出到后续指令的执行环境中。
-p 列出所有的shell赋予程序的环境变量

3、 结论

  • 执行脚本时,是在一个子shell环境运行的,脚本执行完后该子shell自动退出;
  • 一个shell中的系统环境变量才会被复制到子shell中(用export定义的变量);
  • 一个shell中的系统环境变量只对该shell或者它的子shell有效,该shell结束时变量消失(并不能返回到父shell);
  • 不用export定义的变量只对该shell有效,对子shell也是无效的。

参考资料

  1. Shell基础教程B站视频地址:请点击这里
  2. export详解参考资料地址:请点击这里

你可能感兴趣的:(Linux学习,bash,开发语言,shell)