一、shell相关概念
交互式与非交互式操作
交互式操作:程序运行后,需要用户输入指令引导程序一步一步地处理。(类似一问一答)。
非交互式操作:程序运行后,无需用户输入指令引导。(类似一问自答)。
shell脚本应用场景
重复性操作
交互性任务
批量事务处理
服务运行状态监控
定时任务执行
脚本的作用:根据编写内容处理交互性任务,方便快捷的解决大量重复的操作。
计算机架构:
底层硬件 -> 操作系统内核 -> 核外程序 -> 计算机用户
在底层硬件之上安装操作系统内核,在内核之上安装核外程序来使用(shell是核外程序),计算机用户通过核外程序来输入指令,shell负责解释用户指令给系统内核,系统内核调用硬件来完成任务。
查看系统都支持哪些shell
cat /etc/shells
[root@localhost ~]# cat /etc/shells
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
查看shell的具体属性,发现sh是bash的软连接,说明sh=bash,两者无区别。
[root@localhost ~]# ll /bin/sh
lrwxrwxrwx. 1 root root 4 12月18日 22:48 /bin/sh -> bash
脚本两种执行方式的区别
执行方式一:在当前shell(终端)执行脚本
./aaa.sh # 需要执行(x)权限
sh aaa.sh
bash aaa.sh
执行方式二:新开一个子shell(终端)运行脚本,执行完退出子shell(终端)。
source aaa.sh
. aaa.sh
标准输入 键盘 1<
标准输出 显示器 0>
标准错误 显示器 2>
重定向
>:正确输出,覆盖。
>>:正确输出,追加。
<:输入,覆盖。
<<:输入,追加。
2>:错误输出,覆盖。
2>>:错误输出,追加。
&>:混合输出,正确+错误。
管道符
|:左边命令输出的结果,作为右边命令的输入。
grep:过滤出满足条件的行。
[root@localhost ~]# tar zcvf aaa.tar.gz /boot
tar: 从成员名中删除开头的“/” # 写绝对路径时,会把根(/)路径删除,避免解压直接解压到原位置。
[root@localhost ~]# tar zxvf aaa.tar.gz
[root@localhost ~]# ls
aaa.tar.gz anaconda-ks.cfg boot pass.txt # 解压后发现boot目录在当前目录下。
grep awk sed 及正则表达式
grep(global regular expression,全局正则表达式):用于过滤满足条件的行。
例如:
grep "root" /etc/shadow 过滤出包含root的行
grep -v "root" /etc/shadow 过滤出不包含root的行 -v:反向查找
awk:文本分析工具。
例如:
[root@localhost ~]# df | grep "/$" | awk '{print $5}' | awk -F % '{print $1}'
2 # /空间使用情况
sed:利用脚本来处理文本文件。
变量:在内存空间中存储的可变化的量,在内存空间中存储的值都会有一个内粗地址,用于标明身份。用户在使用变量值时,如果每次都要查看变量的内存地址,也太不方便了,此时通过输入变量名即可输出在内存空间中对应的内存地址,也就是屏幕上输出的变量值。
变量命名规范
1、不能以数字开头。
2、不能包含特殊符号(如@ $等)。
3、不能是纯数字组合。
设置变量:
变量名=变量值
双引号("):变量值用双引号括起来,代表一个整体,特殊符号具有特殊含义。
例如:aaa=111 name="$aaa",此时echo $name 会输出$aaa的值,即111. 因为name="$aaa",$aaa被双引号括起来,特殊符号$具有特殊含义,表明使用$aaa,所以会输出111.
单引号('):变量值用单引号括起来,代表一个整体,特殊符号没有含义
例如;aaa=222 name='$aaa',此时echo $name 会输出$aaa。因为name='$aaa',$aaa被单引号括起来,特殊符号$不具有特殊含义,$此时只是个普通字符,输出结果自然为$aaa.
反引号(`):变量值是linux命令时需要使用反引号括起来,代表一个整体。或者使用$()将linux命令括起来,也是代表一个整体。
例如:rpm -qf `which useradd` 输出此命令后会显示useradd的rpm包是谁,用反引号括起来linux命令即可使用,如果去掉反引号会报错。
$() 和 `` 的区别:$()支持多层嵌套,反引号只支持一层嵌套,如果语句要使用嵌套格式,选择$()。
例如:多层嵌套使用$()
[root@localhost ~]# rpm -qf $(which useradd)
shadow-4.14.3-5.oe2403sp1.x86_64
[root@localhost ~]# rpm -qc shadow-4.14.3-5.oe2403sp1.x86_64
/etc/default/useradd
/etc/login.defs
[root@localhost ~]# rpm -qc $(rpm -qf $(which useradd)) # 嵌套使用命令
/etc/default/useradd
/etc/login.defs
read:与用户交互,接受用户输入的内容赋值给变量。
语法: read -p "提示信息" 变量名
变量相关:
调用变量时:${变量名}
{}:变量名要用{}括起来,代表一个整体。
全局变量:在任何终端都可用。
局部变量:只在当前shell终端可用。
export 变量名 将已有的局部变量声明为全局变量。
export 变量名=变量值 设置变量时就将该变量声明为全局变量。
环境变量是一个总称,代表系统变量和用户变量。
系统变量:系统级别的变量,更改此变量会影响所有系统用户。系统变量中通常存储了系统命令的搜索路径。
用户变量:用户级别的变量,更改此变量只会影响该用户。用户变量中通常存储了该用户自定义的搜索路径。
数值运算相关:
expr
+:加
-:减
*:乘
/:除
%:取余
语法: expr 变量 运算符 变量 注意空格
set:显示系统中所有的环境变量,包括全局变量和局部变量。
env:显示当前的全局变量。
优化系统路径(path)的方式:
cp 脚本名 /usr/local/sbin 1、复制所需脚本到/bin或/sbin下。
软链接 脚本名 /usr/local/sbin 2、软链接方式
vim /etc/profile PATH=$PATH:/路径 source /etc/profile 3、写入系统变量
位置参数 $0 $1 的区别
$0代表当前执行的进程/程序名
$1代表第一个位置参数
$#:命令行中位置变量的个数。
$*:所有位置变量的内容。
$?:上一条命令执行后返回的状态,当返回状态值为0时表示执行正常,非0值表示执行异常或出错。
$0:当前执行的进程/程序名。
二、脚本示例
一、脚本两种执行方式的区别
[root@localhost ~]# cat aaa.sh
#!/bin/bash # 脚本第一行为说明信息,告诉系统这个脚本需要什么解释器来执行。
cd /boot
pwd
ls -l
[root@localhost ~]# . aaa.sh
/boot
总计 163988
-rw-r--r--. 1 root root 238365 12月27日 12:19 config-6.6.0-72.0.0.76.oe2403sp1.x86_64
drwxr-xr-x. 2 root root 4096 12月24日 10:47 dracut
drwxr-xr-x. 3 root root 4096 2025年 3月 1日 efi
drwx------. 6 root root 4096 2025年 3月 1日 grub2
-rw-------. 1 root root 65022738 2025年 3月 1日 initramfs-0-rescue-8c899201cf284bc98f5ef36f063fcc14.img
-rw-------. 1 root root 30258146 2025年 3月 1日 initramfs-6.6.0-72.0.0.76.oe2403sp1.x86_64.img
-rw-------. 1 root root 36850688 2025年 3月 1日 initramfs-6.6.0-72.0.0.76.oe2403sp1.x86_64kdump.img
drwxr-xr-x. 3 root root 4096 2025年 3月 1日 loader
drwx------. 2 root root 16384 2025年 3月 1日 lost+found
-rw-r--r--. 1 root root 312306 12月27日 12:19 symvers-6.6.0-72.0.0.76.oe2403sp1.x86_64.gz
-rw-r--r--. 1 root root 6949973 12月27日 12:19 System.map-6.6.0-72.0.0.76.oe2403sp1.x86_64
-rw-r--r--. 1 root root 14119392 2025年 3月 1日 vmlinuz-0-rescue-8c899201cf284bc98f5ef36f063fcc14
-rw-r--r--. 1 root root 14119392 12月27日 12:19 vmlinuz-6.6.0-72.0.0.76.oe2403sp1.x86_64
[root@localhost boot]#
执行完脚本,工作路径换到了boot。
[root@localhost ~]# ./aaa.sh
/boot
总计 163988
-rw-r--r--. 1 root root 238365 12月27日 12:19 config-6.6.0-72.0.0.76.oe2403sp1.x86_64
drwxr-xr-x. 2 root root 4096 12月24日 10:47 dracut
drwxr-xr-x. 3 root root 4096 2025年 3月 1日 efi
drwx------. 6 root root 4096 2025年 3月 1日 grub2
-rw-------. 1 root root 65022738 2025年 3月 1日 initramfs-0-rescue-8c899201cf284bc98f5ef36f063fcc14.img
-rw-------. 1 root root 30258146 2025年 3月 1日 initramfs-6.6.0-72.0.0.76.oe2403sp1.x86_64.img
-rw-------. 1 root root 36850688 2025年 3月 1日 initramfs-6.6.0-72.0.0.76.oe2403sp1.x86_64kdump.img
drwxr-xr-x. 3 root root 4096 2025年 3月 1日 loader
drwx------. 2 root root 16384 2025年 3月 1日 lost+found
-rw-r--r--. 1 root root 312306 12月27日 12:19 symvers-6.6.0-72.0.0.76.oe2403sp1.x86_64.gz
-rw-r--r--. 1 root root 6949973 12月27日 12:19 System.map-6.6.0-72.0.0.76.oe2403sp1.x86_64
-rw-r--r--. 1 root root 14119392 2025年 3月 1日 vmlinuz-0-rescue-8c899201cf284bc98f5ef36f063fcc14
-rw-r--r--. 1 root root 14119392 12月27日 12:19 vmlinuz-6.6.0-72.0.0.76.oe2403sp1.x86_64
[root@localhost ~]#
执行完脚本,工作目录未发生改变。
二、重定向
[root@localhost ~]# setenforce 0 # 关闭后才可以使用stdin来实现脚本创建用户和创建用户密码。
[root@localhost ~]# vim bbb.sh
#!/bin/bash
useradd ooos
passwd --stdin ooos < pass.txt # 重定向输入
[root@localhost ~]# cat pass.txt
123
[root@localhost ~]# chmod +x bbb.sh
[root@localhost ~]# ./bbb.sh
更改用户 ooos 的密码 。
passwd:所有的身份验证令牌已经成功更新。
[root@localhost ~]# ls -l > 1.txt
[root@localhost ~]# ls -l > 1.txt
[root@localhost ~]# ls -l > 1.txt
[root@localhost ~]# ls -l > 1.txt # 将标准输出重定向覆盖输出至1.txt
[root@localhost ~]# ls
1.txt aaa.sh anaconda-ks.cfg bbb.sh pass.txt
[root@localhost ~]# cat 1.txt
总计 16
-rw-r--r--. 1 root root 0 3月 1日 10:45 1.txt
-rwxr-xr-x. 1 root root 31 3月 1日 10:30 aaa.sh
-rw-------. 1 root root 1271 2025年 3月 1日 anaconda-ks.cfg
-rwxr-xr-x. 1 root root 56 3月 1日 10:37 bbb.sh
-rw-r--r--. 1 root root 4 3月 1日 10:37 pass.txt
[root@localhost ~]# ls -l >> 1.txt
[root@localhost ~]# ls -l >> 1.txt
[root@localhost ~]# ls -l >> 1.txt # 将标准输出重定向追加输出至1.txt
[root@localhost ~]# cat 1.txt
总计 16
-rw-r--r--. 1 root root 0 3月 1日 10:46 1.txt
-rwxr-xr-x. 1 root root 31 3月 1日 10:30 aaa.sh
-rw-------. 1 root root 1271 2025年 3月 1日 anaconda-ks.cfg
-rwxr-xr-x. 1 root root 56 3月 1日 10:37 bbb.sh
-rw-r--r--. 1 root root 4 3月 1日 10:37 pass.txt
总计 20
-rw-r--r--. 1 root root 286 3月 1日 10:46 1.txt
-rwxr-xr-x. 1 root root 31 3月 1日 10:30 aaa.sh
-rw-------. 1 root root 1271 2025年 3月 1日 anaconda-ks.cfg
-rwxr-xr-x. 1 root root 56 3月 1日 10:37 bbb.sh
-rw-r--r--. 1 root root 4 3月 1日 10:37 pass.txt
总计 20
-rw-r--r--. 1 root root 572 3月 1日 10:47 1.txt
-rwxr-xr-x. 1 root root 31 3月 1日 10:30 aaa.sh
-rw-------. 1 root root 1271 2025年 3月 1日 anaconda-ks.cfg
-rwxr-xr-x. 1 root root 56 3月 1日 10:37 bbb.sh
-rw-r--r--. 1 root root 4 3月 1日 10:37 pass.txt
总计 20
-rw-r--r--. 1 root root 858 3月 1日 10:47 1.txt
-rwxr-xr-x. 1 root root 31 3月 1日 10:30 aaa.sh
-rw-------. 1 root root 1271 2025年 3月 1日 anaconda-ks.cfg
-rwxr-xr-x. 1 root root 56 3月 1日 10:37 bbb.sh
-rw-r--r--. 1 root root 4 3月 1日 10:37 pass.txt
[root@localhost ~]# fsadfadsfa 2> 2.txt
[root@localhost ~]# fsadfadsfa 2> 2.txt
[root@localhost ~]# fsadfadsfa 2> 2.txt
[root@localhost ~]# fsadfadsfa 2> 2.txt
[root@localhost ~]# fsadfadsfa 2> 2.txt # 将错误输出重定向覆盖输出到2.txt
[root@localhost ~]# cat 2.txt
-bash: fsadfadsfa: 未找到命令
[root@localhost ~]# fsadfadsfa 2>> 2.txt
[root@localhost ~]# fsadfadsfa 2>> 2.txt
[root@localhost ~]# fsadfadsfa 2>> 2.txt
[root@localhost ~]# fsadfadsfa 2>> 2.txt # 将错误输出重定向追加输出到2.txt
[root@localhost ~]# cat 2.txt
-bash: fsadfadsfa: 未找到命令
-bash: fsadfadsfa: 未找到命令
-bash: fsadfadsfa: 未找到命令
-bash: fsadfadsfa: 未找到命令
-bash: fsadfadsfa: 未找到命令
[root@localhost ~]# ls -a /root sdfdsf &> 4.txt # 混合(正确+错误)输出到4.txt
[root@localhost ~]# cat 4.txt
ls: 无法访问 'sdfdsf': No such file or directory
/root:
.
..
1.txt
2.txt
3.txt
4.txt
aaa.sh
anaconda-ks.cfg
.bash_logout
.bash_profile
.bashrc
bbb.sh
.cshrc
pass.txt
.ssh
.tcshrc
.viminfo
[root@localhost ~]# read -p ":" aaa # read输出提示符并等待用户赋值给变量
:123
[root@localhost ~]# echo $aaa
123
三、expr运算表达式
[root@localhost ~]# x=20
[root@localhost ~]# y=6
加法:
[root@localhost ~]# expr $x + $y
26
减法:
[root@localhost ~]# expr $x - $y
14
乘法:
[root@localhost ~]# expr $x * $y
expr: 语法错误:未预期的参数 "1.txt"
[root@localhost ~]# expr $x \* $y # \转义字符,取消*的特殊含义,使其作为乘。
120
取余:
[root@localhost ~]# expr $x % $y
2