文章目录
前言
总结了一下Shell脚本的基础知识,都结合了示例,通俗易懂。一. Shell基础
shell是命令解释器的一个总称

计算机是由计算机硬件组成的,但是人类无法直接使用硬件,于是就产生了操作系统内核来控制计算机硬件,但是操作系统内核也不能被人们直接操作,例如我们所熟知的window系统和Linux系统,这些就是通过用户应用程序来控制系统内核的,众所周知计算机只能识别0和1,而命令解释器就是用来将人类自然语言转化为计算机能识别语言(0和1)的媒介,当然,不同的命令也有不同的解释器,常见的解释器有:
- /bin/bash (常用的)
- /bin/sh
- /bin/csh
- /bin/tcsh
解释器负责将用户的指令翻译为内核可以识别的指令。
通过usermod,chsh可以更改登录Shell。
下面说一下关于解释器的一些操作
1. 查看
我们可以 输入 cat /etc/shells 来查看我们拥有那些解释器

2. 安装
我们可以通过输入 yum -y install xxx 来安装我们想要的解释器、

3. 使用
我们可以通过输入 usermod -s 解释器名字 用户名 来使用这个解释器
然后输入 grep 用户名 /etc/passwd 来查看当前正在使用的解释器

也可以使用 chsh -s 解释器名字 用户名 将解释器修改回来

4. Bash基本特性
Bash的作为默认的解释器自然有他的道理,下面就来解释一下,Bash解释器的一些特别之处。
Bash解释器具有许多方便的快捷键
- Ctrl + a :移到命令行首
- Ctrl + e :移到命令行尾
- Ctrl + r:逆向搜索命令历史
- Ctrl + l:清屏
- Ctrl + o:执行当前命令,并选择上一条命令
- Ctrl + s:阻止屏幕输出
- Ctrl + q:允许屏幕输出
- Ctrl + c:终止命令,将我们当前执行的命令撤销掉
- Ctrl + z:挂起命令
- Ctrl + g:从历史搜索模式退出
- Ctrl + f :按字符前移(右向)
- Ctrl + b :按字符后移(左向)
- Alt + f :按单词前移(右向)
- Alt + b :按单词后移(左向)
- Ctrl + xx:在命令行首和光标之间移动
- Ctrl + u :从光标处删除至命令行首
- Ctrl + k :从光标处删除至命令行尾
- Ctrl + w :从光标处删除至字首
- Alt + d :从光标处删除至字尾
- Ctrl + d :删除光标处的字符
- Ctrl + h :删除光标前的字符
- Ctrl + y :粘贴至光标后
- Alt + c :从光标处更改为首字母大写的单词
- Alt + u :从光标处更改为全部大写的单词
- Alt + l :从光标处更改为全部小写的单词
- Ctrl + t :交换光标处和之前的字符
- Alt + t :交换光标处和之前的单词
- Alt + Backspace:与 Ctrl + w 相同类似
- 还有 Tab 快速补全代码快捷键,可以大大的减少我们的代码编辑量
查看历史命令
可用通过上下键来查看使用过的命令记录,对于一些的重复的命令我们就不必再去敲一遍了。
命令别名
有些命令具有别名 比如 ll = ls -l
也就是给一个命令又起了个名字,简写了,我们也可以自己创建别名,来提高编辑代码的速率。
标准输入输出的重定向
把输出不显示到屏幕上而显示到文件中
使用 `>` 将输出显示在文件中,同时 `>` 也意味着**覆盖**文件中以前的内容,使用 `>>` 才是在原内容上**追加**的意思


并不是所以的输出信息都可以用 >或者>>添加到文件中,以上正常的输出可以,但是错误的输出 就不行了

我们可以用 2>来将错误的输出添加到文件中

但如果又有错误又有正常输出信息呢?我们该如何把他们存放到文件中?
我们可以使用 &> 将他们一块儿存入文件中,同样的一个 > 都是覆盖,>> 是追加


管道
管道可以联合多条命令,将第一条命令的结果给第二条命令使用
比如我们来实行一下 过滤操作 ,从yum 列表中筛选出含有 bash 的软件
yum list | grep bash

二. hello world
我们还是先从创建第一个 hello world 开始
首先创建一个脚本:文件
shell/day1 是我提前创建好的目录

vim /root/shell/day1/first.sh
按s 插入Shell命令
echo "hello world -tom"

按Esc 输入 :x保存并退出
然后给脚本添加可执行权限
chmod +x /root/shell/day1/first.sh
下一步 就可以执行这个脚本了
vim /root/shell/day1/first.sh

在上面步骤中有关键的一步 ,就是给脚本文件可执行权限 ,其实有一种方法,可以不用给权限还能运行脚本
在不具有可执行权限时,我们可以用下面方法执行脚本
- 解释器 脚本文件名 例如 :bash first.sh
- source 脚本文件名 这种方法不会启动子进程,我们可以通过 pstree(需要下载)查看进程树来观察不同。
三. 变量
1. 自定义变量
定义变量
变量名=变量值
取消变量
unset 变量名
变量规范
- 变量 = 两边不能加空格,不能使用关键字做变量名,如ls,cd等等。
- 如果变量名已经存在则覆盖以前的变量名 。
- 变量名称只能由字母数字下划线组成,而且不能以数字开头。
- 在打印一个变量的时候,最好用
{}括起来

2. 环境变量
变量名为大写,由操作系统维护 ,这些都是系统提前设置好的变量
- 存储在/etc/profile或~/.bash_profile中
- 命令env可以列出所有的环境变量
- 常见的环境变量有:PATH,PWD,USER,UID,HOME,SHELL
PATH:命令搜索变量,负责搜索命令是否存在
PWD:显示当前所在路径的变量
USER:显示当前用户名
UID:显示当前用户的ID号
HOME:当前用户的家目录
SHELL:显示当前正在使用的解释器

3. 位置变量
bash内置变量 ,存储脚本执行时的参数
使用$n表示,n为数字序列号,如果n<10用 $n表示 ,如果n>10,用 ${n}表示
下面就来演示一下位置变量的使用方法:
先创建一个脚本文件
vim /root/shell/day1/a.sh
然后在脚本文件中设置 三个位置变量
echo $1
echo $2
echo $3

然后再给文件 可执行 权限
chmod +x /root/shell/day1/a.sh
最后 给位置变量赋值,再执行脚本文件
/root/shell/day1/a.sh aa bb cc
第一个位置变量 aa , 第二个位置变量 bb,第三个位置变量cc。

4. 预定义变量
bash内置变量,可以调用,但不能赋值和修改,用来保存脚本程序的执行信息。
| 变量名 | 含义 |
|---|---|
| $0 | 当前所在的进程或脚本名 |
| $$ | 当前运行进程的PID号 |
| $? | 命令执行后的返回状态,0表示正常,1或其他值表示异常,只针对上一条命令 |
| $# | 以加载的位置变量的个数 |
| $* | 所有位置变量的值 |
下面是$?用法和其余几个的用法

错误显示非0,正常显示0

后面aa bb cc dd是4个位置变量的值
5. 单引号和双引号的区别
下面来举个例子

可以看出 "" 可以识别特殊符号 而 ' ' 不能识别特殊符号
其中还有 `` 反引号 与 $() 等效 ,引号和括号内都是命令, 整体得到的是命令执行的结果(a= $(),a得到的是括号内命令执行的结果)
6. 变量使用实例
read的使用
将输入的值赋给后面的变量
例如
read -p "请输入用户名:" username

会把提示后的输入的值赋给变量 username
但如果不给提示加双引号,会出现下面情况

如果我们设置输入密码
read -s -p "请输入密码:" password
前面加上-s 在我们输入时就不显示输入的内容了 安全性高点

read 还有一个 -t方法 ,限定在多少秒内输入 ,否者就退出输入
read -t 3 -p "请输入用户名:" username
限定用户三秒内 输入

局部变量和全局变量
局部变量 : 新定义的变量默认只在当前的Shell环境中生效,无法在子Shell环境中使用
全局变量 :全局变量在当前Shell和子Shell环境中均有效
设置一个局部变量
a=11
在当前的Shell中有效,但在bash中无效

下面我们设置一个全局变量
export b=22
可以看出在当前Shell中有效,在bash中也有效

四. Shell中基本运算
1. 整数运算
Shell 中有 + - * / %(取余)
下面演示一下
主要的执行方式 有两种
- $(())
- $[]

同时也支持一些简写表达式
| 简写表达式 | 完整表达式 |
|---|---|
| i++ | i=i+1 |
| i- - | i=i-1 |
| i+=2 | i=i+2 |
| i-=2 | i=i-2 |
| i*=2 | i=i*2 |
| i/=2 | i=i/2 |
| i%=2 | i=i%2 |

2. 小数运算
Bash内建机制仅支持整数运算,不支持小数运算,我们可以通过计算机软件bc实现小数运算
bc支持交互式和非交换式两种方式计算,scale=n可以约束小数位
交互执行

非交互执行

bc也同样支持比较操作符
表达式成立返回1,不成立返回0

五. 条件测试
1. test测试操作
语法格式
test 选项 参数[ 选项 参数 ]
基本语法:
是否为空[ -z 字符串 ]
等于 [ 字符串1 == 字符串2 ]
不等于[ 字符串1!= 字符串2 ]

显示 0 为正确

显示 非0 为不成立
2. 整数值比较
格式:[整数值1 操作符 整数值2]
| 操作符 | 含义 |
|---|---|
| -eq | 等于 |
| -ne | 不等于 |
| -ge | 大于或等于 |
| -le | 小于或等于 |
| -gt | 大于 |
| -lt | 小于 |
应用

2 大于 1 ,输出 0符合
2 不大于 3, 输出 1(非0)不符合
3. 文件状态测试
| 操作符 | 含义 |
|---|---|
| -e | 判断对象是否存在,若存在则结果为真 |
| -d | 判断对象是否为目录 |
| -f | 判断对象是否为一般文件 |
| -r | 判断对象是否有可读权限 |
| -w | 判断对象是否有可写权限 |
| -x | 判断对象是否有可执行权限 |
应用
/etc/ 为存在对象
/eeee/ 不纯在

4. 组合命令
我们可以使用控制符将多个命令组合
格式 : 命令1 控制符 命令2
控制符有:
;: 前后两个命令没有逻辑关系,先执行前面的命令,然后再执行后面的命令,无论前面的命令是否执行成功 ,都会执行后面的命令。&&: 先执行前面的命令,然后再执行后面的命令,唯有前面的命令成功,才会执行后面的命令。||:先执行前面的命令,然后再执行后面的命令,当前面的命令执行成功时,便不在执行后面的命令,只有前面的命令执行不成功,才会执行后面的命令
应用
先进入 /root/shell 目录,再查看目录内容,会显示day1

打印 day1 表示 两条命令执行成功
我们也可利用 && 和 || 来实现多个条件的判断
[判断1] || [判断2]
[判断1] && [判断2]
5. 监控脚本基础知识
tr -s :删除多余重复的字符
例如 将 “a b c”中多余重复的空格去掉
echo "a b c" | tr -s " "

最终字母之间都只留下了一个空格
cut过滤
格式 : cut -d分割符号 -第几列 目标文件
类如 我们以 /etc/passwd 为目标文件,以 : 为分隔符号 ,获取第一列内容
cut -d: -f1 /etc/passwd


六. if语句
1. 单分支if语句
格式1:
if 条件
then 命令
fi
格式2:
if 条件 ;then
命令
fi
两种格式都可以使用 ,如果条件成立,执行命令,否者什么也不做。
下面来写一个创建用户脚本
条件为用户名和密码都不能为空,命令是创建用户并修改密码,最后的 echo 打印空 ,也就是换行。
由于 read pass 带了 -s 所以输入的密码不显示,实际是输入了密码。
read -p "请输入用户名:" user
read -s -p "请输入密码:" pass
if [ ! -z "$user" ]&&[ ! -z "$pass" ];then
useradd "$user"
echo "$pass" | passwd --stdin "$user"
fi
echo


2. 双分支if语句
格式1:
if 条件
then 命令1
else
命令2
fi
格式2:
if 条件;then
命令1
else
命令2
fi
格式3:
if 条件1;then
命令1
elif 条件2; then
命令2
......
else
命令n+1
fi
下面写一个例子:
测试主机是否能ping通
#!/bin/bash
if [ -z "$1" ];then
echo -n "用法:脚本"
echo -e "\033[32m域名或IP\033[0m"
exit
fi
ping -c2 -i0.1 -W1 "$1" &>/dev/null
if [ $? -eq 0 ];then
echo "$1 is up"
else
echo "$1 is down"
fi
echo
-c2 :ping两次结束
-i0.1:ping的间隔是0.1秒
-W1 :ping的反应时间为1秒,若ping的反应时间超过1秒,默认ip ping不通
当我们什么都不输入时,会提示格式,当我们随便输入一个ip,显示ip 关闭 ,当我们输入自己的ip时显示 ip 开启

七. for 循环
根据变量的不同取值,重复执行命令序列
格式1:
for 变量 in 值列表
do
命令
done
格式2:
for ((初值;条件;步长))
do
命令
done
下面举个例子(格式1)
#!/bin/bash
for i in 1 23 abc 2g
do
echo "I am $i"
done

可以看出循环执行了5次,将in后内容遍历了一遍
格式1中的值列表有多种表示方式,也可以这样写
for i in {1..10}
for i in {a..z}
for i in {A..Z}
表示1到10,a到z,A到Z

下面再举个例子(格式2)
#!/bin/bash
for((i=1;i<=5;i++))
do
echo "I am $i"
done
这个就不必多说了。

99乘法表
下面来运用for循环的格式2来写一个99乘法表
#!/bin/bash
for((i=i;i<=9;i++))
do
for((j=1;j<=i;j++))
do
echo -n "$i*$j=$[i*j]"
done
echo
done

八. while循环
条件式循环,反复测试条件,只要成立就执行命令序列。
格式:
while 条件
do
命令
done
举个例子
遍历输出1-5
#!bin/bash
i=1
while [$i -le 5 ]
do
echo $i
let i++
done

猜数字游戏
给出一个10以内的随机数让玩家猜,如果输入的数大于随机数,会显示猜大了,如果输入的数小于随机数,则显示猜小了。
#!/bin/bash
num=$[RANDOM%10+1]
while:
do
read -p "请输入1-10之间的整数:" guess
if [$guess -eq $num ];then
echo "恭喜你,猜对了"
exit
elif [ $guess -lt $num ];then
echo "猜小了"
else
echo "猜大了"
fi
done

九. case语句
效果类似于多分支的if语句,如果与预设的值相匹配,则执行相应的操作,命令最后以 ; 结尾,如果都不匹配,则执行默认命令。
格式:
case 变量 in
模式1)
命令1;;
模式2)
命令2;;
......
*)
默认命令
esac
举一个例子
输入 tom 输出 I am tom ,输入tome 输出 I am tome ,输入其他的 则 输出 暂无此人。
#!/bin/bash
read -p "请输入tom 或者 tome:" key
case $key in
tom)
echo "I am tom";;
tome)
echo "I am tome";;
*)
echo "暂无此人"
esac

石头剪刀布游戏
运用数组和case语句来创造一个石头剪刀布游戏脚本,系统会随机选择出拳的方式。
#!/bin/bash
gane=(石头 剪刀 布)
num=$[RANDOM%3]
computer=${game[$num]}
#通过随机数获取系统的出拳
#出拳的可能保存在一个数组中:game[0],game[1],game[2]
echo "请根据下列提示选择您的出拳方式"
echo "1.石头"
echo "2.剪刀"
echo "3.布"
read -p "请选择1-3:" person
case $person in
1)
if [ $num -eq 0];then
echo "平局"
elif [ $num -eq 1 ];then
echo "你赢"
else
echo "电脑赢"
fi;;
2)
if [ $num -eq 0 ];then
echo "电脑赢"
elif [ $num -eq 1 ];then
echo "平局"
else
echo "你赢"
fi;;
3)
if [ $num -eq 0 ];then
echo "你赢"
elif [ $num -eq 1 ];then
echo "电脑赢"
else
echo "平局"
fi;;
*)
echo "必须输入1-3的数字"
esac

数组
数组是一个特殊的变量,它是能够储存多个数据的集合
格式:
数组名=(数值1 数值2 数值3 ...)
下面来演示一下
创建一个名为 test 的数组

十. shell函数
在Shell环境中,将一些需要重复使用的操作,定义为公共的语句块,既可称为函数
格式1:
function 函数名{
命令
...
}
格式2:
函数名(){
命令
...
}
范例
不带参数的函数
imsg(){
echo "hello world"
echo "compute cloud"
}

带参数的函数
add(){
echo $[$1+$2]
}

带颜色的函数
\033[:开启设置字体颜色
\033[0m : 关闭设置字体颜色
#!/bin/bash
cecho(){
echo -e " \033[$1m$2\033[0m"
}
cecho 31 OK #参数是字体的颜色
cecho 32 OK
cecho 33 OK
cecho 34 OK

十一. 中断和退出
脚本中的中断和退出命令
continue : 可以结束单次循环
break :可以结束循环体
exit :可以退出脚本
下面举几个例子
首先是continue ,当遍历到 3 时,跳过本次循环

然后是 break
当遍历到 3 时跳出循环

最后是 exit
如果是在脚本文件中,会退出脚本,如果在xshell中直接exit,则会退出连接。

十二. 字符串的处理和变量的初始化
统计变量长度
test=123456789
echo ${#test}

1. 字符串的截取
格式:${变量:起始位置:长度}
text=123456789
从第0位开始往后截取3位
echo ${test:0:3}

从第3位开始,往后截取3位
echo ${test:3:3}

从第四位开始,截取到最后一位
echo ${test:4}

从第四位开始,截取到倒数第二位
echo ${test:4:-2}

2. 字符串的替换
替换一个结果
格式:${变量/旧字符/新字符}
替换全部结果
格式:${变量//旧字符/新字符}
示例

3. 字符串的掐头去尾
掐头
字符串的掐头都是从左到右,且不会改变变量原来的值
最短匹配
格式 : ${变量#关键词}
最长匹配
格式:${变量##关键词}
举例
定义变量 test=123:456:789
分别最短匹配掐头和最长匹配掐头
*:表示 :前面的所有部分

去尾
去尾的顺序是从右往左,同样不会改变变量原来的值
最短匹配
格式: ${变量%关键词}
最长匹配
格式:${变量%%关键词}
举例
与上面的例子差不多
因为顺序改变了,所以 * 的位置也变了一下

4. 变量初始化
判断一个变量是否有值,如果有值返回该变量的值,如果没有值,则返回初始值
格式:${变量:-初始值}
示例
此处给a变量赋值,b没有赋值,使用变量格式化,a返回原有的值,b返回变量初始化的值。

5. 随机密码
定义变量:10个数字+52个字母,用随机数对62取余数,返回的结果为[0-61],然后将其作为key的字符串位数取出字符,随机取10次,得到一个10位的随机密码。
#!/bin/bash
key="1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
pass=""
for i in {1..10}
do
num=$[RANDOM%${#key}]
tmp=${key:num:1}
pass=${pass}${tmp}
done
echo $pass

使用命令生成随机密码
- uuidgen:生成随机序列号
- openssl: 生成可控长度的随机序列号,例子后面的15不是指的序列号的长度,而是一个控制值,值越大,序列号越长。

使用随机设备文件生成随机密码
/dev/random : 能够一直产生随机码,不会自动终止,效率很慢,大概十几秒出一次。

/dev/urandom: 这个文件也能源源不断的产生随机码,而且效率很高。

十三. 正则表达式
描述一个字符集合的表达方式,根据特征模糊的匹配内容。
1. 基本正则符号
| 正则符号 | 描述 |
|---|---|
| abc | 匹配abc |
| ^ | 匹配开头 |
| $ | 匹配结尾 |
| [集合] | 匹配集合中的任意单个字符 |
| [ ^ 集合] | 对集合取反 |
. | 匹配任意单个字符 |
| * | 匹配前一个字符任意次(包含0次) |
.* | 匹配任意 |
| {n,m} | 匹配前一个字符n到m次 |
| {n,} | 匹配前一个字符至少n次 |
| {n} | 匹配前一个字符n次 |
2. 扩展正则符号
| 正则符号 | 描述 |
|---|---|
| + | 匹配前面的字符至少一次 |
| ? | 匹配前面的字符0或一次 |
| () | 组合与保留 |
| | 或者 |
| {n,m} | 匹配前面的字符n到m次 |
| {n,} | 匹配前面的字符至少n次 |
| {n} | 匹配前面的字符n次 |
3. Perl兼容的正则符号
| 正则符号 | 描述 |
|---|---|
| \b | 匹配单词边界 |
| \w | 匹配字符数字下划线 |
| \W | 和\w相反 |
| \s | 匹配空白 |
| \d | 匹配数字 |
| \d+ | 匹配多个数字 |
| \D | 匹配非数字 |
4. grep语法
grep语法支持正则表达式,下面介绍一下grep语法,以及一些正则表达式的练习示例。
格式: grep [选项] 匹配模式 [文件]...
常用的选项:
-i:忽略大小写
-v:取反匹配(全部)
-w:匹配单词
-q:静默匹配,不将结果显示在屏幕上
下面来介绍一些练习的指令
创建一个名为 test.txt 的文件,并在里面写上足够的内容
- 过滤文件中 带 the 的行
grep the test.txt

- 过滤文件中带 the 的行,不区分大小写
grep -i the test.txt

- 过滤包含数字的行
grep "[0-9]" test.txt
grep -P "\d" test.txt

- 过滤包含 in和the 的行
grep -E "(in|the)" test.txt

- 过滤包含两个 o 的行
grep "o\{2\}" test.txt
- 过滤以大写字母开头的行
grep "^[A-Z]" test.txt
- 过滤 ou 前面不是th的行
grep -E "[^(th)]ou" test.txt
- 过滤不以 . 结尾的行
grep "[^.]$" test.txt
- 过滤以 .结尾的行
grep "\.$" test.txt
- 过滤空白行
grep "^$" test.txt
- 过滤以数字开始的行
grep "^[0-9]" test.txt
- 过滤所有的字母
grep "[a-zA-Z]" test.txt
- 过滤所有符号
grep -P "\W" test.txt
十四. sed基础
Stream Editor,流式编辑器,非交互式,对文档的处理是逐行处理,可以对文本进行增删改查等操作。
语法格式:
sed [选项] '[定位符]指令' 文件名
命令 | sed [选项] '[定位符]指令'
常用命令选项 :
- -n:屏蔽默认输出
- -i:直接修改源文件
- -r:支持扩展正则
常用的sed指令:
- p (print): 打印行
- d (delete) :删除行.
- c (replace) :替换行
- s (substitution) :替换关键词
- i (insert):插入
- a (append) :追加
- r (read):读取文件|导入文件内容
- w (write) :文件另存为导出文件内容
- = : 打印行号
1. 打印文件内容
示例
-n : 默认屏蔽输出,控制只打印所需内容,若不加,则会把所有内容都打印出来。
‘3p’ : 3表示第三列,p表示打印 。
打印文件指定内容
sed -n '3p' /etc/passwd

从第一行打印到第三行
sed -n '1,3p' /etc/passwd

从第二行开始,步长为2,也就是打印2 4 6 8 …偶数行
sed -n '2~2p' /etc/passwd
打印第2行以及后面的3行
sed -n '2,+3p' /etc/passwd
打印1,3,6行内容
sed -n '1p;3p;6p' /etc/passwd
打印除2以外的所有行
sed -n '2!p' /etc/passwd
打印包含 root 的行
sed -n '/root/p' /etc/passwd
2. 正则定位
从文件中过滤包含3个数字的行,运用正则表达式定位
sed -rn '/[0-9]{3}/p' /etc/passwd

3. 删除文件内容
删除文件内所有内容(谨慎使用)
不加 -i 对源文件不会有影响
sed -i 'd' /etc/hosts
删除1-3行
sed -i '1,3d' /etc/hosts
删除所有不包含dev的行
sed -i '/dev/!d' /etc/hosts
删除所有以 # 开头的行
sed -i '/^#/d' /etc/hosts
删除所有空白行
sed -i '/^$/d' /etc/hosts
4. 替换文件内容
不使用 -i,源文件不会被改变
将所有的行替换为123456
sed -i 'c 123456' /etc/hosts
将第3行改为12345
sed -i '3c 123456' /etc/hosts
通过观察可以看出,格式都大同小异,只是命令和sed指令改变了而已
5. 替换文件内关键词
不加 -i 对源文件不会有影响
将每一行的第1个123都替换成xxx
sed -i 's/123/xxx/' /etc/hosts
将每一行的第2个123都替换成xxx
sed -i 's/123/xxx/2' /etc/hosts
将所有的123都替换成xxx
sed -i 's/123/xxx/g' /etc/hosts
将第2行的123都替换成xxx
sed -i '2s/123/xxx/g' /etc/hosts
将第2行的123都替换成空(也就是删掉)
sed -i '2s/123//g' /etc/hosts
6. 文件中插入内容
不加 -i 对源文件不会有影响
在第二行前插入 123
sed -i '2i 123' /etc/hosts
在含有abc那一行的前面插入123
sed -i '/abc/i 123' /etc/hosts
在第二行后追加 123
sed -i '2a 123' /etc/hosts
在含有abc那一行的后面追加123
sed -i '/abc/a 123' /etc/hosts
7. 文件导入内容
不加 -i 对源文件不会有影响
在 test.txt 文件内容的第2行后面插入 /etc/hosts 文件内容
sed -i '2r /etc/hosts' test.txt
在 test.txt 文件内容的 含有abc的 那一行 后面插入 /etc/hosts 文件内容
sed -i '/abc/r /etc/hosts' test.txt
8. 文件内容导出
将指定文件内容导出,存到另一个文件中去,如果目标文件不存在,系统会自动创建。
不加 -i 对源文件不会有影响
将 test.txt 文件的内容导出另存到 copy_test.txt 文件中去
sed -i 'w copy_test.txt' test.txt
将test.txt文件的2-4行 另存到文件line.txt中
sed -i '2,3w line.txt' test.txt
将test.txt文件的所有包含abc的行 另存到文件abc.txt中
sed -i '/abc/w abc.txt' test.txt
十五. awk基础
数据处理引擎,基于模式匹配检查输入文本,逐行处理并输出,通常用在Shell脚本中,获取指定的数据,单独用时,可对文本数据做统计。
格式1:前置命令 | awk [选项] ‘[条件]{指令}’
格式2:awk [选项] ‘[条件]{指令}’ 文件...
补充:
- 指令可以是多条语句,但语句之间要用
;隔开 - 条件如果不写的话,默认全部逐行处理。
awk的内置变量
| 内置变量 | 含义 |
|---|---|
| FS | 保存或设置字段分隔符,例如FS= “:”,与-F功能一样 |
| $n | 指定分隔的第n个字段,如$1、$3分别表示第1、第3列 |
| $0 | 当前读入的整行文本内容 |
| NF | 记录当前处理行的字段个数(列数) |
| NR | 记录当前已读入行的数量(行数) |
示例:
先创建一个文件 test1.txt 有以下内容

以空格为分割符,逐行打印文件内容的第1列和第3列
awk '{print $1,$3}' test1.txt

把文件中的空格改为:,以 :为分隔符打印第2列
awk -F: '{print $2}' test1.txt

打印文件当前处理的行,和本行有几列
awk -F: '{print NR,NF}' /etc/passwd

打印常量用户名和UID
awk -F: '{print "用户名:"$1,"UID:"$3}' /etc/passwd

1. awk过滤的时机
- BEGIN{} :在所有行前处理,读入第一行文本之前执行,一般用来初始化操作。
- {} : 逐行处理,逐行读入文本执行相应的处理,最常见的编译指令块。
- END{} : 在所有行后处理,处理完最后一行文本后执行,一般用来输出处理结果。
示例
开始结束执行文件时打印行数
awk -F: 'BEGIN{print NR} END{print NR}' /etc/passwd

统计有多少行含有bash,在开始设置变量x,逐行读取,满足条件x加1,最后打印出x的值

2. awk条件判断
格式 :awk [选项] ‘[条件]{指令}’ 文件...
举例
打印带root的行
awk -F: '/root/{print}' /etc/passwd

打印一切不是bash结尾的行
awk -F: '$71~/bash$/{print}' /etc/passwd
打印第二行内容
awk -F 'NR==2' /etc/passwd
将文件内容任意一行第三列的值大于等于0小于2的值打印出来
awk -F: '$3>=0&&$3<2{print$1,$3}' /etc/passwd

将第三列等于1或者等于7的内容打印出来
awk -F: '$3==1||$3==7{print$1,$3}' /etc/passwd
3. awk流程控制
单分支if判断
格式: awk '{指令}' 文件
示例
如果 第三列大于等于1000 那么i+1,最后输出i的值
awk -F: '{if($3>=1000){i++}} END{print i}' /etc/passwd
将 uptime中cpu的负载管道给awk,如果最后一列负载大于0.01则输出负载
uptime|awk '{if($NF>0.01){print "CPUload:"$NF}}'
双分支if判断
举例
第三列大于等于1000的为普通用户,小于1000的为系统用户,统计普通用户和系统用户的个数
awk -F: '{if($3>=1000){i++}else{j++}}END{print "普通用户:"i,"系统用户:"j}' /etc/passwd

多分支if判断
举例
设定 以-开头的是普通文件,以d开头的是目录,判断各种的个数
ls -l /etc | awk '{if($1~/^-/){x++} else if($1~/^d/){y++} else{z++}}END{print "普通文件个数:"x,"目录个数:"y,"其他个数:"z}'

4. awk的for循环
awk的for循环采用的和c语言一样的语法格式
for(表达式1;表达式2;表达式3){指令}
举例
awk 'BEGIN{ for(i=1;i<5;i++){print i}}'

5. awk数组
定义:数组名[下标]=元素值
调用:数组名[下标]
遍历:for(变量名 in 数组名){print 数组名[变量]}
示例
定义与调用
awk 'BEGIN{name[0]="jim";name[1]="tom";print name[1],name[0]}'

其数组下标也不一定要为数字,也可以为字符串
awk 'BEGIN{age["tom"]=22;age["jim"]=18;print age["tom"],age["jim"]}'

遍历的使用
awk 'BEGIN{ x[0]=0;x[1]=1;x[2]=2;x[3]=3;for(i in x){print x[i]}}'

十六. 综合实例
1. 循环嵌套
打印星星矩阵
连续打印5组每行有5列的星星
#!/bin/bash
for i in {1..5}
do
echo -n "*"
done
echo
echo
for i in {1..5}
do
for j in {1..5}
do
echo -n "*"
done
echo
done

排列和组合
打印所有1-3的组合方式
#!/bin/bash
for i in {1..3}
do
for j in {1..3}
do
echo "${i}${j}"
done
done

打印梯形
#!/bin/bash
for ((i=1;i<=6;i++))
do
for((j=1;j<=i;j++))
do
echo -ne "\033[101m \033[0m"
done
echo
done

打印对称梯形
for ((i=1;i<=6;i++))
do
for((j=1;j<=i;j++))
do
echo -ne "\033[101m \033[0m"
done
echo
done
for ((i=1;i<=5;i++))
do
for((j=5;j>=i;j--))
do
echo -ne "\033[101m \033[0m"
done
echo
done

2. 带菜单的脚本
#!/bin/bash
echo "1.查看剩余内存容量"
echo "2.查看根分区剩余容量"
echo "查看CPU十五分钟负载"
echo "4.查看系统进程数量"
echo "5.查看系统账户数量"
echo "6.退出"
while :
do
read -p "请输入选项[1-6]:" key
case $key in
1)
free | awk '/Mem/{print $NF}';;
2)
df | awk '/\/$/{print $4}';;
3)
uptime | awk '{print $NF}';;
4)
ps aux | wc -l;;
5)
sed -n '$=' /etc/passwd;;
6)
exit
esac
done

3. 备份数据
date=$(date +%Y%m%d)
if [ ! -f /tmp/log-$date.tar.gz ];then
tar -czf /tmp/log-$date.tar.gz /var/log
fi

4. 安全脚本
HASH值: HASH值与文件名称,时间,大小等信息无关,仅与内容有关
如果文件内容没有发生改变,HASH不变,否者改变。我们可以用MD5,SHA256,SHA512来计算哈希值。
主要用来校对文件拷贝后是否发生错误导致拷贝文件变化。
计算某一文件的HASH值
当某一文件被恶意篡改时,我们不用逐个打开文件比较内容,而直接可以比较哈希值,来确定被修改文件。
md5sum /etc/passwd

举例
将etc目录下所有文件的哈希值存入data.log文件中
#!/bin/bash
for i in $(ls /etc/*.conf)
do
md5sum $1 >> /tmp/data.log
done

5. 格式化输出passwd
awk -F: 'BEGIN{print"用户名 UID 家目录"} {print $1,$3,$6}' /etc/passwd | column -t

从/etc/passwd中将所有能登陆的账户名提取出来,并从/etc/shadow中提取账户对应的密码
#!/bin/bash
USER=$(awk -F: '/bash$/{print $1}' /etc/passwd)
for i in $USER
do
awk -F: -v iuser=$i '$1==iuser {print $1,$2}' /etc/shadow
done

本文详细介绍了Linux Shell的基础知识,包括Shell的查看、安装和使用,特别是Bash的基本特性和快捷键。此外,还讲解了变量、运算、条件测试、循环结构、字符串处理和正则表达式等核心概念,是学习Linux Shell操作的全面教程。

2522

被折叠的 条评论
为什么被折叠?



