一天学会shell编程

Shell编程

一、特殊状态变量

$?: 上一次命令执行的状态的返回值,0正确,非0失败

$$: 当前shell脚本的进程号

$!:上一次后台进程的 PID

$_: 取得上次命令,最后一个参数

​ 查找方式 man bash

​ 搜索Special Parameters

$#:获取参数的总个数

脚本控制返回值的玩法,脚本返回值,学习shell函数编程之后,才能彻底理解

这个脚本执行完毕,会返回一个数字id,称之为返回值

#! /bin/bash

[ $# -ne 2] && {
	echo "must be two args"
	exit 119
}
echo ok

如何让程序后台执行

nohub xxx &1> /dev/null

#!/bin/bash

[ $# -ne 2 ] && {
    echo "must be two args"
    exit 119
}

echo ok

echo "当前的脚本id:$$"

二、Shell子串

bash一些基础的内置命令

echo
eval
exec
export
read
shift

1、echo命令

-n 不换行输出
-e 解析字符串中的特殊符号
\n 换行
\r 回车
\t 制表符 四个空格
\b 退格

2、eval:执行多个命令

[root@localhost sh]# eval ls; ps
hello.sh  test1.sh
  PID TTY          TIME CMD
 3370 pts/1    00:00:00 bash
12185 pts/1    00:00:00 man
12207 pts/1    00:00:00 less
17341 pts/1    00:00:00 gdb
17870 pts/1    00:00:00 netstat
19690 pts/1    00:00:00 tcp_server
20745 pts/1    00:00:00 ps

exec:不创建子进程,执行后续命令,且执行完毕后,自动exit

三、Shell 子串的花式用法

1、基础语法

${变量} 					返回变量值
${#变量}					返回变量的长度,字符长度
${变量:start}     		返回变量start数值之后的字符
${变量:start:length}      提取start之后的length限制的字符
${变量#word}      		从变量开头删除最短匹配的word子串
${变量##word}				从变量开头,删除最长匹配的word
${变量%word}				从变量结尾开始删除最短的word
${变量%%word}				从变量结尾开始删除最长匹配的word
${变量/pattern/string}    用string代替第一个匹配的pattern
${变量//pattern/string}   用string代替所有的pattern

用于接收脚本文件执行时传入的参数
$0 用于获取当前脚本文件名称的
$1~$9, 代表获取第一输入参数到第9个输入参数
第10个以上的输入参数获取参数的格式: ${数字}, 否则无法获取

2、子串的实际案例

​ Shell截取字符串通常有两种方式:从指定为位置开始截取和指定的字符(子字符串)开始截取。

​ 从指定的位置开始截取。

​ 这种方式需要两个参数除了指定起始位置,还需要截取长度,才能最终确定要截取的字符串。

​ 既然需要指定起始位置,那么就涉及到计数方向的问题,到底是从字符串左边开始计数,还是从字符串右边开始计数,还是从字符串右边开始计数。shell同时支持两种技术方式。

​ 1)从字符串左边开始计数

​ 如果从字符串的左边开始计数,那么截取的字符串的具体格式如下:

${string:start :length}

​ 其中,string 是要截取的字符串,start是起始位置(从左边开始,从0开始计数),length是要截取的长度(省略的话表示直到字符串的末尾)。

​ music_name = “大约在冬季”

# 基础语法 用法
[root@localhost sh]# echo ${name}
120asdasdasd
# 计算长度
[root@localhost sh]# echo ${#name}
12
[root@localhost sh]#
[root@localhost sh]# echo ${name:2}
0asdasdasd
[root@localhost sh]# echo ${name:2:2}
0a
[root@localhost sh]# echo ${name#120}
asdasdasd
[root@localhost sh]# echo ${name##asd}
120asdasdasd
[root@localhost sh]# echo ${name##120asd}
asdasd
[root@localhost sh]# echo ${name##12}
0asdasdasd
[root@localhost sh]# echo ${name%asd}
120asdasd
[root@localhost sh]# echo ${name%%asd}
120asdasd
[root@localhost sh]# echo ${name/asd/aini}
120ainiasdasd
[root@localhost sh]# echo ${name//asd/aini}
120ainiainiaini

3、计算变量长度的各种玩法

  • 多种统计长度的命令
  • 统计命令执行速度
echo $name  | wc -L # 输出最长的行数
echo $name  | wc -l # 输出行数
# 利用数值计算
expr length "${name}"
# awk统计长度
echo "${name}" | awk '{print length()}'
# 最快的统计方式
echo ${#name}

time命令,统计命令执行时长

for循环的shell编程知识

语法:

for 变量 in 1-100

for number in {1…100}

do

xxx

done

for num in {1..100};do echo $num;done 
# 写在一行的方法

seq 生成序列,默认以空格。

seq -s ":" 10
[root@localhost sh]# for n in {1..3};do str1=`seq -s ":" 10`;echo $str1;done
1:2:3:4:5:6:7:8:9:10
1:2:3:4:5:6:7:8:9:10
1:2:3:4:5:6:7:8:9:10

# 结合time命令
[root@localhost sh]# time for n in {1..10000};do char=`seq -s "chao" 100`;echo ${#char} &>/dev/null;done

real    0m14.142s # 实际运行时间
user    0m4.269s  # 用户态执行时间
sys     0m9.838s  # 内核态执行时间

# 使用完成 wc-L 计算时间
[root@localhost sh]# time for n in {1..10000};do char=`seq -s "chao" 100`;echo ${char}|wc -L &>/dev/null;done

real    0m38.628s
user    0m15.194s
sys     0m30.241s

# 使用expr命令的length
[root@localhost sh]# time for n in {1..10000};do char=`seq -s "chao" 100`;expr length "${char}" &>/dev/null;done

real    0m25.441s
user    0m8.868s
sys     0m17.513s
# 使用awk
[root@localhost sh]# time for n in {1..10000};do char=`seq -s "chao" 100`;echo "${name}" | awk"{print length()\}" &>/dev/null;done

real    1m57.223s
user    0m46.885s
sys     1m5.295s


shell编程,尽量使用Linux内置命令,内置的操作,和内置的函数,效率最高C语言开发,效率最高,尽可能的减少,管道符的操作。

4、字符串截取

a*c  匹配开头为a,中间任意个字符,结尾为c的字符串

实际练习

# 删除匹配的字符

[root@localhost sh]# name="I am chaoge"
[root@localhost sh]# echo ${name:2:2}
am
[root@localhost sh]# echo ${name:3:5}
m cha

[root@localhost sh]# name2="abcABC123ABCabc"
[root@localhost sh]# echo ${name2#a*c}
ABC123ABCabc
[root@localhost sh]# echo ${name2##a*c}
[root@localhost sh]# echo ${name2#a*C}
123ABCabc
[root@localhost sh]# echo ${name2##a*C}
abc

[root@localhost sh]# echo ${name2%a*c}
abcABC123ABC
[root@localhost sh]# echo ${name2%%a*c}
[root@localhost sh]# echo ${name2%%a*C}
abcABC123ABCabc
[root@localhost sh]# echo ${name2%a*C}
abcABC123ABCabc

替换字符串

# 替换字符串
[root@localhost sh]# unset str1 # 去除已有值的变量

[root@localhost sh]# str1="Hello,man,i am your brother."
[root@localhost sh]# echo $str1
Hello,man,i am your brother.
[root@localhost sh]# echo ${str1/man/girl}
Hello,girl,i am your brother.
[root@localhost sh]# echo ${str1//o/O}
HellO,man,i am yOur brOther.

5、删除文件名的案例

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gCjU7H72-1692256124101)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230804101730067.png)]

1、去掉所有文件的_finished的后缀

​ 思路:

​ 单个文件去掉字符

[root@localhost tes]# mv chaochao_1_finished.jpg chaochao_1.jpg
[root@localhost tes]# ls
chaochao_1_finished.png  chaochao_3_finished.jpg  chaochao_5_finished.jpg
chaochao_1.jpg           chaochao_3_finished.png  chaochao_5_finished.png
chaochao_2_finished.jpg  chaochao_4_finished.jpg
chaochao_2_finished.png  chaochao_4_finished.png
[root@localhost tes]# ls -l
total 0
-rw-r--r--. 1 root root 0 Aug  4 09:46 chaochao_1_finished.png
-rw-r--r--. 1 root root 0 Aug  4 09:46 chaochao_1.jpg
-rw-r--r--. 1 root root 0 Aug  4 09:46 chaochao_2_finished.jpg
-rw-r--r--. 1 root root 0 Aug  4 09:46 chaochao_2_finished.png
-rw-r--r--. 1 root root 0 Aug  4 09:46 chaochao_3_finished.jpg
-rw-r--r--. 1 root root 0 Aug  4 09:46 chaochao_3_finished.png
-rw-r--r--. 1 root root 0 Aug  4 09:46 chaochao_4_finished.jpg
-rw-r--r--. 1 root root 0 Aug  4 09:46 chaochao_4_finished.png
-rw-r--r--. 1 root root 0 Aug  4 09:46 chaochao_5_finished.jpg
-rw-r--r--. 1 root root 0 Aug  4 09:46 chaochao_5_finished.png

2、利用变量的子串功能,去掉后缀

​ 利用/来替换空

[root@localhost tes]# f=chaochao_1_finished.png
[root@localhost tes]# echo ${f//_finished/}
chaochao_1.png

3、利用反引号的功能

当你在 Shell 脚本中使用反引号 ` 可以将其内部的命令执行,并将命令的输出结果作为替换返回。

[root@localhost tes]# mv $f `echo ${f//_finished/}`

4、批量修改文件名,只修改所有的jpg文件

[root@localhost tes]# for file_name in `ls *fin*.jpg`;do mv $file_name `echo ${file_name//_finished/}`;done
[root@localhost tes]# ls -l *jpg
-rw-r--r--. 1 root root 0 Aug  4 09:46 chaochao_1.jpg
-rw-r--r--. 1 root root 0 Aug  4 09:46 chaochao_2.jpg
-rw-r--r--. 1 root root 0 Aug  4 09:46 chaochao_3.jpg
-rw-r--r--. 1 root root 0 Aug  4 09:46 chaochao_4.jpg
-rw-r--r--. 1 root root 0 Aug  4 09:46 chaochao_5.jpg

四、特殊shell扩展变量

1、变量处理

​ 这四个扩展变量,都属于对变量的值进行判断、处理

# 如果parameter变量值为空,返回word字符串,赋值给result变量。
result=${parameter:-word}

# 如果parameter变量为空,则word替代变量值,此时parameter的值为word,且返回其值给result。
result=${parameter:=word}

# 如果parameter变量为空,word当作stdrr(错误信息)输出,否则输出变量值用于设置变量为空导致错误时。返回的错误信息。
${parameter:?word}

# 如果parameter变量为空,什么都不做,否则word返回。
${parameter:+word}

2、实际案例

:- 判断变量如果值为空,就返回后面的字符信息,可以通过result变量去接收

:=如果变量为空,后面的值赋值给接收者,以及变量本身

:?当变量值为空的时候,主动抛出的错误信息

:+如果变量为空,什么都不做,否则字符返回为接收者

  • :-的用法
# str变量为空
[root@localhost tes]# result=${str:-123}
[root@localhost tes]# echo $str

[root@localhost tes]# echo $result
123

# str变量不为空
[root@localhost tes]# echo $result
123
[root@localhost tes]# str="1111"
[root@localhost tes]# echo $str
1111
[root@localhost tes]# result=${str:-123}
[root@localhost tes]# echo $result    # 不为空 相当于就是把str的值复制给result
1111

  • :=的用法
# 变量str为空
[root@localhost tes]# result=${str:=123}
[root@localhost tes]# echo $result
123
[root@localhost tes]# echo $str
123

# 变量str不为空的情况,相当于将str的值赋值给result

[root@localhost tes]# unset result
[root@localhost tes]# echo $result

[root@localhost tes]# echo $str
123
[root@localhost tes]# result=${str:=qwq}
[root@localhost tes]# echo $result
123

  • :?的用法
# 变量为空
[root@localhost tes]# echo ${new_name:?}
-bash: new_name: parameter null or not set
[root@localhost tes]# echo ${new_name:?word}
-bash: new_name: word

#变量不为空
[root@localhost tes]# echo ${str:?}
123
[root@localhost tes]# echo ${str:?is error}
123
  • :+的用法
# 值为空,什么都不做
[root@localhost tes]# echo $result

[root@localhost tes]# echo ${result:+hehe}

#值不为空
[root@localhost tes]# result="ping"
[root@localhost tes]# echo ${result:+hehe}
hehe

3、实际应用

数据备份,删除过期的数据的脚本

find xargs # 搜索且删除
# 删除7天以上的过期数据
find 需要搜索的目录 -name 你要搜索的文件名字 -type 文件类型 -mtime +7|xargs rm -f

cat del_data.sh

# 希望删除某个数据文件夹的备份文件
# dir_path="/data/mysql_data"
# 一旦路径出现问题

find ${dir_path:=/data/mysql_data} -name '*.tar.gz' -type -f -mtime +&|xargs rm -f

五、父子Shell

  1. source和点,执行脚本,只在当前的shell环境中生效。
  2. 指定bash sh解释器运行脚本,是开启subshell,开启子shell运行脚本命令。
  3. ./script,都会指定shebang,通过解释器运行,也是开启subshell运行命令

1、父shell的概念

pstree看到如下结果,就是shell环境

[root@localhost tes]# pstree
systemd─┬─ModemManager───2*[{ModemManager}]
        ├─NetworkManager───2*[{NetworkManager}]
        ├─VGAuthService
        ├─2*[abrt-watch-log]

ps 进程管理命令,查看

ps -ef     
# -f 显示UID PID PPID
# -e 列出所有进程的信息,如同-A选项
ps -ef --forest
#--forest 显示父子进程
# 通过一条命令检查父子shell的关系

2、子shell的概念

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e5iL6CPr-1692256124103)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230804141626347.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5Ivc95CP-1692256124104)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230804142722167.png)]

父shell 发出命令 -> 创建子shell 子shell发出命令:

​ bash ps-f

3、多个子shell

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a4Q9Sdj3-1692256124104)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230804142127033.png)]

输出exit,退出子shell环境

4、创建进程列表(创建子shell执行命令)

需要大家,执行一系列的shell命令

ls ;cd ;pwd ;echo "hello"

列表,肯定是被包裹起来的数据

{}()[]

shell的进程列表概念,需要使用()小括号,如下执行方式,就称之为进程列表

加上小括号,就是开启子shell运行

(cd -;pwd;ls;cd;echo "hello")

5、检测是否在子shell环境中

linux 默认有关shell的变量

# 该变量的值特点,如果是0,就是在当前shell环境中执行的,否则就是开辟子shell去运行的。
echo BASH_SUBSHELL
[root@localhost tes]# echo $BASH_SUBSHELL
0

检测是否开启了子shell运行命令

cd ~;pwd;ls;cd Desktop/sh;pwd;ls;echo $BASH_SUBSHELL

[root@localhost tes]# cd ~;pwd;ls;cd Desktop/sh;pwd;ls;echo $BASH_SUBSHELL
/root
anaconda-ks.cfg  Desktop  Documents  Downloads  initial-setup-ks.cfg  Music  perl5  Pictures  Public  Templates  Videos
/root/Desktop/sh
hello.sh  tes  test1.sh
0

明确是开启子shell运行的命令

进程列表,并且开启子shell运行

[root@localhost sh]# (cd ~;pwd;ls;cd Desktop/sh;pwd;ls;echo $BASH_SUBSHELL)
/root
anaconda-ks.cfg  Desktop  Documents  Downloads  initial-setup-ks.cfg  Music  perl5  Pictures  Public  Templates  Videos
/root/Desktop/sh
hello.sh  tes  test1.sh
1

6、子shell嵌套运行

刚才是一个小括号,开启一个子shell运行命令,还可以嵌套多个

(pwd;echo $BASH_SUBSHELL)
[root@localhost sh]# (pwd;echo $BASH_SUBSHELL)
/root/Desktop/sh
1
[root@localhost sh]# ((pwd);(echo $BASH_SUBSHELL))
/root/Desktop/sh
2

利用括号,开启子shell的理念,以及检查,在shell脚本开发中,经常会用子shell进行多进程的处理,提高程序并发执行效率。

六、内置命令、外置变量

内置命令:在系统启动时就加载入内存,常驻内存,执行效率更高,但是占用资源。cd

外置命令:用户需要从硬盘中读取程序文件,再读入内存加载。

外置命令,也称为,自己单独下载的文件系统命令,处于bash shell之外的程序。

# 一般根目录在以下
/bin
/use/bin
/sbin
/usr/sbin

[root@localhost sh]# which cd
/usr/bin/cd

比如ps命令

通过linux的type命令,验证是否是内置、外置命令

[root@localhost sh]# type ps
ps is hashed (/usr/bin/ps)

内置命令

内置命令不会产生子进程去执行

内置命令和shell是为一体的,是shell的一部分,不需要单独去读取某个文件,系统启动后,就执行在内存中了

type命令验证即可

# 查看Linux中内置命令
compgen -b

七、Shell脚本开发

1、知识回顾

执行脚本的方式

source my_first.sh
.my_first.sh

bash my_first.sh
./my_first.sh

[root@localhost sh]# bash my_first.sh
当前时间日期是: Fri Aug  4 15:55:11 CST 2023

在Shell编程中,echo 是一个用于在终端输出文本的命令。它可以用于打印变量、字符串和其他文本内容。以下是一些 echo 命令的示例:

  1. 打印字符串:
echo "Hello, World!"
  1. 打印变量:
name="Alice"
echo "My name is $name"
  1. 打印多行文本:
echo "Line 1
Line 2
Line 3"
  1. 打印特殊字符:
echo "This is a tab:    and this is a newline:\n"
  1. 打印到文件:
echo "Hello, File!" > output.txt
  1. 禁止解释特殊字符(使用单引号):
echo 'This is $name'  # 输出:This is $name

echo 命令可以根据需要进行格式化输出,例如插入变量、换行符和其他控制字符。在实际的Shell脚本中,echo 是一个常用的工具,用于输出信息、调试和日志记录。

echo命令,在linux下的格式化打印

#!/bin/bash
# 这是用于显示日期,和谁登录的脚本
echo "The time and date are:"
date
echo ""
echo "Let's see"
who

# 执行脚本如下
[root@localhost sh]# ./echo_test.sh
The time and date are:
Fri Aug  4 16:23:55 CST 2023

Let's see
root     :0           2023-07-10 18:40 (:0)
root     pts/0        2023-07-10 18:40 (:0)
root     pts/1        2023-08-04 15:00 (10.45.111.27)

echo 能够输出变量的值

#!/bin/bash
#显示你的用户个人信息
echo "User info for username: $USER"
echo "User UID is: $UID"
echo "User Home is:" $HOME

[root@localhost sh]# bash echo_test_var.sh
User info for username: root
User UID is: 0
User Home is: /root

在Shell脚本中,美元符号($)通常用于引用变量的值,以及执行命令并获取其输出。下面是美元符号在Shell中的常见用法:

  1. $variable: 获取变量的值。例如,如果变量name的值是"John",那么$name将会被替换为"John"。
  2. $(command): 执行命令并获取其输出。例如,$(date)将会返回当前日期和时间的输出。
  3. $#: 获取命令行参数的数量。
  4. $0: 获取脚本本身的名称。
  5. $1, $2, …: 获取命令行参数的具体值,例如$1表示第一个参数,$2表示第二个参数,依此类推。
  6. $?: 获取上一个命令的退出状态码。
  7. $$: 获取当前Shell脚本的进程ID。
  8. ${variable}: 在复杂的情况下,可以使用花括号来明确指示变量的边界。

请注意,在某些情况下,美元符号可能需要进行转义,以确保其被正确解释而不是被Shell视为特殊字符。例如,如果要在字符串中显示美元符号本身,可以使用\$来转义。

如果您有更具体的问题或需要特定用法的解释,请随时提问。

echo 和转义符的概念

所谓转义符

“$”

“”

’ ’

[root@localhost sh]# echo "It is a \$100"
It is a $100
[root@localhost sh]# echo "It is a $100"
It is a 00
[root@localhost sh]# echo 'It is a \$100'
It is a \$100
[root@localhost sh]# echo 'It is a $100'
It is a $100

变量在脚本中的使用

变量被引用的时候,会赋予其值,脚本的变量,在shell执行完毕后,就会消失(根据执行方式决定)

当用不同的方式,执行脚本,产生的结果不一样。

[root@localhost sh]# sh make_var.sh
 入职 10[root@localhost sh]# sh make_var.sh
mw 入职 10[root@localhost sh]# echo $names

[root@localhost sh]# source make_var.sh
mw 入职 10[root@localhost sh]# echo $names
mw

在Shell脚本中,变量是用来存储数据值的,您可以通过变量来传递数据、进行计算和控制脚本的行为。以下是在Shell脚本中使用变量的常见方式:

  1. 变量定义和赋值

    name="John"     # 定义变量name并赋值为"John"
    age=25          # 定义变量age并赋值为25
    
  2. 变量引用:(加$符号)

    echo "My name is $name. I am $age years old."
    
  3. 命令替换:您可以将命令的输出结果赋给变量。

    current_date=$(date)   # 获取当前日期并赋给变量current_date
    
  4. 特殊变量

    • $0: 脚本的名称。
    • $1, $2, …: 命令行参数的值。
    • $#: 命令行参数的数量。
    • $?: 上一个命令的退出状态码。
    • $$: 当前脚本的进程ID。
  5. 变量替换:您可以使用${}来引用变量,特别是在某些特定的语境下,例如:

    echo "The value of name is ${name}."
    
  6. 环境变量:系统预定义的一些特殊变量,比如$PATH表示系统的搜索路径,$HOME表示用户的主目录等。

  7. 修改变量值:可以通过赋值来修改变量的值,也可以使用运算符进行计算并重新赋值。

  8. 删除变量:使用unset命令可以删除一个已定义的变量。

  9. 局部变量和全局变量:默认情况下,变量在脚本中是全局的,但您可以使用local关键字在函数内部创建局部变量。

示例:

#!/bin/bash

name="Alice"
age=30

echo "My name is $name. I am $age years old."

current_date=$(date)
echo "Today is $current_date."

echo "Total number of arguments: $#"
echo "Script name: $0"
echo "First argument: $1"
echo "Exit status of last command: $?"

unset name
echo "Name is unset: $name"

这些是Shell脚本中使用变量的一些基本用法,变量在脚本中起着重要的作用,可以帮助您管理和操作数据。

Linux shell 变量替换引用

shell一大特性,就是可以从命令的执行结果,再提取结果,因此特别适合编写脚本

  • $( )
  • `` 反引号

${vars} 取出变量结果

$() 在括号中执行命令 且拿到命令执行结果

``

()

$vars

在Shell脚本中,特殊符号有特定的含义和用途,它们用于执行不同的操作,控制脚本的流程,处理输入输出等。以下是一些常见的Shell中特殊符号的用法:

  1. ** ∗ ∗ :用于引用变量的值,例如: ‘ **:用于引用变量的值,例如:` :用于引用变量的值,例如:variable`。

  2. #:用于注释,忽略后续内容。

  3. !:用于历史命令的引用。例如,!!表示上一个命令,!n表示历史记录中的第n个命令。

  4. &:用于在后台运行命令。例如:command &

  5. *,?,[]:通配符,用于匹配文件名,如*.txt匹配所有以.txt结尾的文件。

  6. {}:用于创建代码块,例如:for i in {1..5}; do echo $i; done

  7. ():用于分组命令,例如:(command1; command2)

  8. ;:用于分隔多个命令,例如:command1; command2

  9. |:管道操作符,用于将一个命令的输出作为另一个命令的输入。例如:command1 | command2

  10. >,>>:重定向输出到文件,>用于覆盖文件内容,>>用于追加到文件。

  11. <:重定向输入,将文件内容作为命令的输入。

  12. &&:逻辑与运算符,用于连接两个命令,当第一个命令成功时才执行第二个命令。

  13. ||:逻辑或运算符,用于连接两个命令,当第一个命令失败时才执行第二个命令。

  14. **** 或 **$( )**:命令替换,用于将命令的输出作为变量的值。例如:result=$(ls)`。

  15. ",':双引号用于保留变量的值,单引号用于完全不解释内容。

  16. ****:转义字符,用于取消特殊字符的意义,例如:\$表示字面量的$

  17. `:用于定义命令替换。

  18. [[,]]:条件测试,类似于[ ],但提供更多的条件测试功能。

这些特殊符号在Shell脚本中起着重要作用,掌握它们的用法可以让您更加有效地编写和执行脚本。注意,某些特殊符号在不同的上下文中可能会有不同的含义和用法。

2、Shell 数值计算

在Shell脚本中进行数值计算可以使用内建的数值计算操作符,这些操作符可以用于整数和浮点数计算。以下是一些常用的Shell数值计算操作符:

  1. 加法 +:用于执行加法操作。

    result=$((2 + 3))
    
  2. 减法 -:用于执行减法操作。

    result=$((10 - 5))
    
  3. 乘法 *:用于执行乘法操作。

    result=$((4 * 6))
    
  4. 除法 /:用于执行除法操作。

    result=$((15 / 3))
    
  5. 取余 %:用于获取除法的余数。

    remainder=$((20 % 7))
    
  6. 指数 **:用于进行乘方运算。

    power=$((2 ** 3))
    
  7. 赋值 =:用于将计算结果赋值给变量。

    result=$((5 + 7))
    
  8. 浮点数计算:Shell默认是以整数进行计算的,如果需要进行浮点数计算,可以使用bc工具。

    result=$(echo "scale=2; 7 / 3" | bc)
    

注意,Shell中的数值计算默认是整数计算,如果需要进行浮点数计算,需要使用额外的工具,如bc。另外,在进行数值计算时,可以使用双括号(( ))来进行数值计算,也可以使用expr命令来执行表达式计算。

以下是一个使用Shell进行数值计算的示例:

#!/bin/bash

# 整数计算
sum=$((5 + 8))
difference=$((15 - 3))
product=$((6 * 4))
quotient=$((20 / 5))
remainder=$((20 % 7))
power=$((2 ** 3))

echo "Sum: $sum"
echo "Difference: $difference"
echo "Product: $product"
echo "Quotient: $quotient"
echo "Remainder: $remainder"
echo "Power: $power"

# 浮点数计算
float_result=$(echo "scale=2; 7 / 3" | bc)
echo "Float Result: $float_result"

在Shell脚本中,您可以根据需要使用这些数值计算操作符来执行不同类型的计算。

脚本开发,复杂的对用户输入判断的脚本开发

  • 脚本的功能,作用以及需求
  • 转换为shell代码

开发一个接受用户输入的数字,且对运算符号判断,最终得出结果的一个计算脚本

1、接收用户输入

2、对用户输入的是不是数字进行判断

3、对输入的运算符号进行判断

4、最终进行结果计算,输出结果

#!/bin/bash

# 脚本开发

print_usage()
{
    printf "Please enter an ineger!\n"
    #给脚本的执行结果,赋予一个状态码,退出码
    exit 1
}


# 接收用户输入的命令,-p参数后面写,给用户看到的提示信息
# read -p "提示信息" 接收用户输入的变量
read -p "Please input your number:"        firstnum

# 进行用户输入的判断
# []里面前后必须有一个空格,是固定语法
# -n 参数是if 的语句,对字符串的判断,如果字符串为空,条件就不成立,如果字符不为空,条件成立
# sed的作用就是把上述字符串"qwe123" 进行替换,把所有的数字替换为空,那么剩下其他非数字内容了

if [ -n "`echo $firstnum|sed 's/[0-9]//g'`" ]
    then
        print_usage
fi
    
# 对用户代码进行判断

#此时对运算符进行输入
read -p "Please input your operator:"        operator


#对运算符进行判断
# 限制在 +-*/ 四个运算符

if [ "$operator" != "+" ] && [ "$operator" != "-" ] && [ "$operator" != "*" ] && [ "$operator" != "/" ]
    then 
        echo "只允许输入+-*/"
        exit 2
fi

# 对第二个变量进行处理
read -p "Please input your number:"        secondnum

if [ -n "`echo $firstnum|sed 's/[0-9]//g'`" ]
    then
        print_usage
fi
       
# 最后进行数值计算,利用双小括号计算

echo "${firstnum}${operator}${secondnum}结果是:$((${firstnum}${operator}${secondnum}))"       


 

PS✨sed 命令

sed(Stream Editor)是一种用于处理文本流的命令行工具,它可以对文本进行编辑、替换、删除、插入等操作。sed命令在Linux和Unix系统中非常常用,它以行为单位进行处理,并且可以根据正则表达式来匹配和处理文本内容。

以下是一些常见的 sed 命令用法:

  1. 替换文本:

    sed 's/old_pattern/new_pattern/g' input_file
    

    这个命令将输入文件中所有匹配 old_pattern 的文本替换为 new_pattern

  2. 删除文本:

    sed '/pattern/d' input_file
    

    这个命令将删除输入文件中匹配 pattern 的所有行。

  3. 插入文本:

    sed 'n i\new_text' input_file
    

    这个命令将在输入文件的第 n 行前插入 new_text

  4. 打印行:

    sed -n 'p' input_file
    

    这个命令将只打印输入文件中的行,不会输出其他信息。

  5. 执行多个命令:

    sed -e 'command1' -e 'command2' input_file
    

    这个命令可以依次执行多个命令。

  6. 使用正则表达式:

    sed 's/pattern/replacement/flags' input_file
    

    正则表达式可以用于更精确地匹配和处理文本。

  7. 保存更改到文件:

    sed -i 's/old_pattern/new_pattern/g' input_file
    

    -i 选项会将更改应用到输入文件中,并保存更改。

这只是 sed 命令的一些基本用法,实际上 sed 可以进行更多的文本处理操作,具体用法可以参考 sed 的官方文档或其他相关资源。

let 是 Bash shell 中的一个内置命令,用于进行算术运算。它允许你在 shell 脚本中进行整数和算术运算,而无需使用外部工具或命令。

let 命令的基本语法如下:

let expression

其中,expression 是要进行算术运算的表达式。在表达式中,可以使用整数、运算符和变量。

以下是一些示例,演示如何使用 let 命令进行算术运算:

# 使用 let 进行加法运算
let "result = 5 + 3"
echo "Result: $result"  # 输出: Result: 8

# 使用变量和乘法运算
num1=10
num2=4
let "product = num1 * num2"
echo "Product: $product"  # 输出: Product: 40

# 使用括号进行复杂的表达式计算
let "result = (num1 + num2) / 2"
echo "Result: $result"  # 输出: Result: 7

# 使用自增运算符
let "num1++"
echo "Incremented num1: $num1"  # 输出: Incremented num1: 11

需要注意的是,let 命令会将表达式中的变量解释为整数。如果你要进行浮点数运算,let 命令就无法满足需求,你可能需要使用其他工具或编程语言来进行浮点数计算。另外,let 命令在执行算术运算时不需要使用 $ 符号来引用变量。

除了 let 命令,还有其他方法可以进行算术运算,如使用双括号 (( ))expr 命令。

#!/bin/bash
#版本变量

Check_URL()
{
    timeout=5
    #定义一个计数器
    fails=0
    success=0

    #循环执行一定命令
    while true
        do
            wget --timeout=${timeout} --tries=1 http://pythonav.cn -q -o /dev/null

            # echo $? -ne 是不等于的意思
            if [ $? -ne 0 ]
                then
                    let fails++
            else
                let success+=1
            fi
        # 判断当成功次数大于等于1的时候
            if [ ${success} -ge 1 ]
                then
                    echo "ok"
                    exit 0
            fi
            if [ ${fails} -ge 2 ]
                then
                    echo "fail"
                    exit -1
            fi
     done


}

Check_URL

expr 命令

expr --help

expr实践

expr 是一个用于执行基本数学和字符串操作的命令行工具。它可以用于在Shell脚本中进行数值计算和字符串处理。

基本的用法如下:

  1. 数值计算:

    result=$(expr 5 + 3)
    echo $result  # 输出:8
    

    支持的运算符包括:加法 +、减法 -、乘法 *、除法 / 和取模 %

  2. 字符串操作:

    str="Hello, World!"
    length=$(expr length "$str")
    echo $length  # 输出:13
    

    字符串操作支持的操作符有:length 获取字符串长度,index STRING SUBSTRING 获取子字符串在字符串中的位置,substr STRING POS LENGTH 获取子字符串,match REGEX STRING 判断字符串是否匹配正则表达式等。

注意事项:

  • 表达式中的运算符和操作数之间需要用空格隔开。
  • 如果表达式中包含特殊字符(如 *),需要使用引号或者反斜杠将表达式括起来,以避免被Shell解释。
[root@localhost sh]# expr 3 '*' 4
12
[root@localhost sh]# expr 3 \* 4
12
  • 还可以逻辑判断
[root@localhost sh]# expr 5 '>' 6
0
[root@localhost sh]# expr 5 '<' 6
1

虽然expr在Shell脚本中可以用于数值计算和字符串操作,但是它有一些限制,如只能处理整数,对于浮点数和高级的字符串操作需要借助其他工具或编程语言来完成。在现代Shell脚本中,常常使用内建的数值计算和字符串操作功能,或者借助其他工具(如awkbcsedgrep等)来完成更复杂的操作。

expr模式匹配

expr命令也支持模式匹配功能

2个特殊符号
冒号,计算字符串的字符数量

.* 任意字符串重复0次或者多次

语法:

expr 字符串 “:” “.*”

expr命令判断文件名后缀是否合法

执行脚本,传入一个文件名,然后判断该文件,是否是jpg文件

找出长度小于5的单词

if 条件判断参数

-le 小于等于

-lt less than 小于

#!bin/bash


for str1 in I am yu chao, I teach you to learn linux.
    do
        if [ `expr length $str1` -lt 5 ]
            then
                echo $str1
        fi
done

[root@localhost sh]# sh length.sh
I
am
yu
I
you
to

bc命令

awk支持数值运算

中括号运算

1、bc命令

bc 是一个用于执行任意精度的数学计算的命令行工具。它支持整数和浮点数计算,并且可以处理较大的数值,不会受到固定位数的限制。bc 的名称代表 “Basic Calculator”,它在很多 Linux 和 Unix 系统中都是预安装的。

你可以在终端中输入 bc 命令进入交互式模式,然后在交互式模式下进行数学计算。以下是一些 bc 命令的基本用法:

  1. 启动 bc 并执行数学计算:

    bc
    2 + 3
    
  2. 使用变量进行计算:

    bc
    x = 5
    y = 3
    x * y
    
  3. 使用函数进行计算:

    bc
    sqrt(25)
    
  4. 设置小数位数:

    bc
    scale = 2  # 设置小数位数为 2
    10 / 3
    
  5. 退出 bc 交互式模式:

    bc
    quit
    

此外,你还可以将 bc 与其他命令和脚本结合使用,例如从文件中读取表达式并执行计算,或者在脚本中调用 bc 进行动态计算。

请注意,bc 的语法与常见的编程语言有些不同,因此在使用之前最好查阅其文档以了解更多用法和功能。

[root@localhost sh]# echo '4*4' | bc
16

bc案例

# 利用{}来生成
[root@localhost sh]# echo {1..10}
1 2 3 4 5 6 7 8 9 10
[root@localhost sh]# echo {1..10} | tr " " "+"           # tr将空格替换成+
1+2+3+4+5+6+7+8+9+10
[root@localhost sh]# echo {1..10} | tr " " "+" | bc
55

[root@localhost sh]# seq 10
1
2
3
4
5
6
7
8
9
10
[root@localhost sh]# seq -s "+" 10
1+2+3+4+5+6+7+8+9+10
[root@localhost sh]# seq -s "+" 10 | bc
55
[root@localhost sh]# echo $((`seq -s "+" 10`))
55


# expr命令计算,这里有点复杂,expr命令是接受多个参数来计算的
# expr接受以空格分割的,多个参数
# linux下构造参数的命令 xargs


awk 计算

支持小数计算

[root@localhost sh]# echo "3.2 2.2" | awk '{print $1+$2}'
5.4
[root@localhost sh]# echo "3.2 2.2" | awk '{print $1*$2}'
7.04
[root@localhost sh]# echo "3.2 2.2" | awk '{print $1**$2}'
12.922

中括号计算

[root@localhost sh]# num=9
[root@localhost sh]# res=$[num*4]
[root@localhost sh]# echo $res
36

注:

grep 是一个常用的文本搜索工具,用于在文件中查找指定的文本模式,并将匹配的行输出。它通常用于在命令行中搜索文件内容,也可以在脚本中用于处理文本数据。

基本的用法如下:

grep PATTERN FILE

其中,PATTERN 是要搜索的文本模式,FILE 是要搜索的文件名。

例如:

grep "keyword" file.txt

此命令将在 file.txt 文件中搜索包含 "keyword" 的行,并将匹配的行输出。

常用的选项和用法有:

  • -i:忽略大小写。
  • -r:递归地搜索目录下的所有文件。
  • -l:只输出匹配的文件名,而不显示匹配的行。
  • -n:显示匹配行的行号。
  • -v:反转匹配,输出不包含模式的行。
  • -w:只匹配整个词。
  • -e PATTERN:指定多个模式。

例如:

grep -i "error" log.txt  # 在log.txt中搜索包含"error"的行,忽略大小写
grep -rn "pattern" ./    # 在当前目录及其子目录中递归搜索指定模式
grep -l "success" *.log  # 输出所有包含"success"的日志文件名

grep 是一个非常有用的文本搜索工具,可以帮助用户快速定位文件中的特定内容。它在Linux系统中广泛使用,适用于各种文本处理任务。

3、Shell条件判断

读取用户输入

read也是内置命令

-p 设置提示信息

-t 等待用户输入超时,timeout

read -p “请输入:” vars

shell提供条件测试的语法

test命令

[ ]中括号

test条件测试

​ test命令评估一个表达式,它的结果是真,还是假,如果条件为真,那么命令执行状态码结果为0,否则就是不为0,通过$?取值

test命令的参数

-e 判断该文件是否存在 ,(普通文件,目录),存在就为真

# 结果为真
[root@localhost sh]# test -e test1.sh
[root@localhost sh]# echo $?
0
# 结果为假
[root@localhost sh]# test -e test2.sh
[root@localhost sh]# echo $?
1

`test` 命令是 Linux/Unix 系统中用于测试文件或条件的命令,也可以使用 `[ ]` 方括号来代替。它常用于 shell 脚本中的条件判断语句。下面是 `test` 命令常用的参数:

1. `-e FILE`:判断文件是否存在,存在返回真。
2. `-f FILE`:判断文件是否存在并且为常规文件,是则返回真。
3. `-d FILE`:判断文件是否存在并且为目录,是则返回真。
4. `-s FILE`:判断文件是否存在并且非空,是则返回真。
5. `-r FILE`:判断文件是否存在并且可读,是则返回真。
6. `-w FILE`:判断文件是否存在并且可写,是则返回真。
7. `-x FILE`:判断文件是否存在并且可执行,是则返回真。
8. `-z STRING`:判断字符串是否为空,是则返回真。
9. `-n STRING`:判断字符串是否非空,是则返回真。
10. `STRING1 = STRING2`:判断两个字符串是否相等,是则返回真。
11. `STRING1 != STRING2`:判断两个字符串是否不相等,是则返回真。
12. `INT1 -eq INT2`:判断两个整数是否相等,是则返回真。
13. `INT1 -ne INT2`:判断两个整数是否不相等,是则返回真。
14. `INT1 -gt INT2`:判断 INT1 是否大于 INT2,是则返回真。
15. `INT1 -lt INT2`:判断 INT1 是否小于 INT2,是则返回真。
16. `INT1 -ge INT2`:判断 INT1 是否大于等于 INT2,是则返回真。
17. `INT1 -le INT2`:判断 INT1 是否小于等于 INT2,是则返回真。
18. `! EXPRESSION`:逻辑非,如果表达式为假,则返回真。
19. `EXPRESSION1 -a EXPRESSION2`:逻辑与,如果两个表达式都为真,则返回真。
20. `EXPRESSION1 -o EXPRESSION2`:逻辑或,如果两个表达式之一为真,则返回真。

注意,`test` 命令可以直接使用 `[ ]` 方括号来代替,例如 `[ -e FILE ]` 等同于 `test -e FILE`。在条件判断语句中,可以使用 `&&` 来表示逻辑与,`||` 表示逻辑或,例如 `if [ -f file ] && [ -r file ]` 可以判断文件是否存在且可读。

-e判断文件是否存在,存在返回真


[root@localhost sh]# test -e "tes"
[root@localhost sh]# echo $?
0
[root@localhost sh]# test -e "tes" && echo ""

[root@localhost sh]# test -e "tes" && echo "uuuuu"
uuuuu
[root@localhost sh]# test -e "tes" ||  echo ""
[root@localhost sh]# test -e "tes" ||  echo "ee"
[root@localhost sh]# test -e "teqs" ||  echo "ee"
ee


-f判断文件是否存在并且为常规文件

[root@localhost sh]# test -f "tes"
[root@localhost sh]# test -f "tes" || echo "no"
no
[root@localhost sh]# test -f "test1.sh" || echo "no"
[root@localhost sh]# test -f "test1.sh" &&  echo "no"
no
[root@localhost sh]# ls
caculation.sh  echo_test.sh  echo_test_var.sh  hello.sh  length.sh  make_var.sh  my_first.sh  nginx_status.sh  okup  sum.sh  tes  test1.sh
[root@localhost sh]# test -f "hello.sh" &&  echo "no"
no
[root@localhost sh]# test -f "hello.sh" &&  echo "no"
no
[root@localhost sh]# test -f "hello.sh" &&  echo "yes" || echo "no"
yes
[root@localhost sh]# test -f "tes" &&  echo "yes" || echo "no"
no
[root@localhost sh]#

-d 判断文件是否存在并且为目录

[root@localhost sh]# test -d "tes" &&  echo "yes" || echo "no"
yes
[root@localhost sh]# test -d "test1.sh" &&  echo "yes" || echo "no"
no

-z 判断字符串是否为空,是则返回真

-n 判断字符串是否非空,是则返回真

[root@localhost sh]# test -z "" && echo "yes" || echo "no"
yes
[root@localhost sh]# test -z " " && echo "yes" || echo "no"
no

[root@localhost sh]# test -n " " && echo "yes" || echo "no"
yes
[root@localhost sh]# test -n "" && echo "yes" || echo "no"
no

中括号 [ ] 条件测试

脚本中经常进行条件测试,用的最多的,都是中括号[ ]

test和[ ]的作用是一样的

注意的点:中括号,前后的空格必须有

[ -n “filename” ]

注意!!!

在条件测试中使用变量,必须添加双引号

[ -n “$filename” ]

[root@localhost sh]# [ -e "file1" ] && echo "yes" || echo "no"
no
[root@localhost sh]# [ -e "$file1" ] && echo "yes" || echo "no"
yes
[root@localhost sh]# [ -f "$file1" ] && echo "yes" || echo "no"
yes
[root@localhost sh]# file2=cc.sh
[root@localhost sh]# [ -f "$file2" ] && echo "yes" || echo "no"
no
[root@localhost sh]# [ -f "$file2" ] && echo "yes" || echo "no"
no

双中括号

[[ 条件表达式 ]]

验证文件是否有权限,写入权限

注意:root 超级用户

需要切换普通用户

在 Shell 脚本中,你可以使用不同的方式进行字符串比较测试。以下是几种常见的字符串比较测试方式:

  1. 使用 [ ] 方括号和 =!= 进行比较:

    # 检查字符串是否相等
    if [ "$str1" = "$str2" ]; then
        echo "Strings are equal"
    fi
    
    # 检查字符串是否不相等
    if [ "$str1" != "$str2" ]; then
        echo "Strings are not equal"
    fi
    
  2. 使用 test 命令的 =!= 进行比较:

    # 检查字符串是否相等
    if test "$str1" = "$str2"; then
        echo "Strings are equal"
    fi
    
    # 检查字符串是否不相等
    if test "$str1" != "$str2"; then
        echo "Strings are not equal"
    fi
    
  3. 使用双括号 (( )) 进行字符串比较:

    # 检查字符串是否相等
    if (( "$str1" == "$str2" )); then
        echo "Strings are equal"
    fi
    
    # 检查字符串是否不相等
    if (( "$str1" != "$str2" )); then
        echo "Strings are not equal"
    fi
    
  4. 使用 [[ ]] 双括号进行字符串比较:

    # 检查字符串是否相等
    if [[ "$str1" == "$str2" ]]; then
        echo "Strings are equal"
    fi
    
    # 检查字符串是否不相等
    if [[ "$str1" != "$str2" ]]; then
        echo "Strings are not equal"
    fi
    

注意,这些比较都是基于字符串内容的,如果需要进行空字符串判断,可以使用 -z 来判断字符串是否为空,或者使用 -n 判断字符串是否非空。例如:

# 检查字符串是否为空
if [ -z "$str" ]; then
    echo "String is empty"
fi

# 检查字符串是否非空
if [ -n "$str" ]; then
    echo "String is not empty"
fi

需要根据具体的情况选择适合的字符串比较方式。

注意:

  • 对于字符串变量的比较
  • 一定要记住给变量添加双引号
  • 使用等于号的值判断,左右两边必须有空格
[root@localhost sh]# [ "yuchao" = "yuhchao" ] && echo ok || echo no
no
[root@localhost sh]# [ "yuchao" = "yuchao" ] && echo ok || echo no
ok
[root@localhost sh]# name1=yuchao
[root@localhost sh]# [ "$name1" = "yuchao" ] && echo ok || echo no
ok
[root@localhost sh]# name1=wuyanzu
[root@localhost sh]# [ "$name1" = "yuchao" ] && echo ok || echo no
no
[root@localhost sh]# [ "$name1" != "yuchao" ] && echo ok || echo no
ok
[root@localhost sh]# name1=yuchao
[root@localhost sh]# [ "$name1" != "yuchao" ] && echo ok || echo no
no

&& || 逻辑运算

#! /bin/bash

read -p "please input a char:" var1

# 逻辑条件测试

[ "$var1" -eq "1" ] && {
    echo $var1
    exit 0
}


[ "$var1" = "2" ] && {
    echo $var1
    exit 0
}

# 只能输入的是1 或者 2 ,否则就报错

[ "$var1" != "2" -a "$var1" != "1" ] && {
    echo "脚本出错"
    exit -1
}

[root@localhost sh]# sh test_and_or.sh
please input a char:1
1
[root@localhost sh]# sh test_and_or.sh
please input a char:2
2
[root@localhost sh]# sh test_and_or.sh
please input a char:3
脚本出错

#### 安装lnmp/lamp 脚本

cat <<END 是一种 shell 脚本中的输入重定向方式,用于从脚本中提供多行输入内容。在这种情况下,脚本会等待用户输入直到遇到指定的终止符(在这里是 END),然后将输入内容传递给 cat 命令。

例如,以下是一个使用 cat <<END 的简单示例:

#!/bin/bash

cat <<END
This is line 1.
This is line 2.
This is line 3.
END

在这个示例中,脚本会输出三行文本,分别是 “This is line 1.”、“This is line 2.” 和 “This is line 3.”。注意,END 的位置表示输入的终止符,在这之后的内容都会被视为输入内容,直到遇到 END

这种方式对于需要在脚本中插入多行文本或配置文件等内容非常有用,避免了使用多次 echo 或手动输入的麻烦。

# 1、模拟创建出2个安装的脚本lnmp.sh lamp.sh
# 2、开发逻辑判断脚本
#! /bin/bash

# 判断目录是否存在
path=/root/Desktop/sh/shell_program/test_scripts

# 条件判断
# 开发脚本,真和假两种情况,优先处理错误的逻辑情况,错误的情况最容易处理
[ ! -d "$path"  ] && mkdir $path -p


# 开发该脚本的正常脚本

cat <<END 
    1.[install lamp]
    2.[install lnmp]
    3.[exit]
    please input the num you want:

END

read num


# 根据该num变量进行逻辑处理

expr $num + 1 &> /dev/null

# 判断上条命令的结果
# 限制用户输入的必须是数字
[ $? -ne 0 ] && {
    echo "The num you input must be {1|2|3}"
    exit 1
}

# 对输入的数字是1 2 3 进行判断

[ "$num" -eq "1" ] && {
    echo "Starting installing lamp...waiting..."
    sleep 2;
    
    # 执行lamp.sh 安装脚本
    # 对文件权限进行判断
    [ -x "$path/lamp.sh" ] || {
        echo "The file does not exist or can't be exec"
        exit 1
    }
    
    $path/lamp.sh
    exit $?
}

# 开发选择2的情况,安装lamp
[ "$num" -eq "2" ] && {
    echo "Starting installing lnmp...waiting..."
    sleep 2;
    
    [ -x "$path/lamp.sh" ] || {
        echo "The file does not exist or can't be exec"
        exit 1
    }
    $path/lnmp.sh
    exit $?
}

# 退出
[ "$num" -eq "3" ] && {
    echo "byebye."
    exit 3
}

# 限制用户必须输入的是1 2 3 
# [[]] 支持正则表达式 [[ $num =~ [1-3] ]] 

[[ ! $num =~ [1-3] ]] && {
    echo "The num you input must be {1|2|3}"
    
}
 

运行:

[root@localhost test_scripts]# sh lamp_or_lnmp.sh
    1.[install lamp]
    2.[install lnmp]
    3.[exit]
    please input the num you want:

4
The num you input must be {1|2|3}
[root@localhost test_scripts]# sh lamp_or_lnmp.sh
    1.[install lamp]
    2.[install lnmp]
    3.[exit]
    please input the num you want:

w
The num you input must be {1|2|3}
[root@localhost test_scripts]# sh lamp_or_lnmp.sh
    1.[install lamp]
    2.[install lnmp]
    3.[exit]
    please input the num you want:

3
byebye.
[root@localhost test_scripts]# sh lamp_or_lnmp.sh
    1.[install lamp]
    2.[install lnmp]
    3.[exit]
    please input the num you want:

2
Starting installing lnmp...waiting...
LNMP is installed
[root@localhost test_scripts]# sh lamp_or_lnmp.sh
    1.[install lamp]
    2.[install lnmp]
    3.[exit]
    please input the num you want:

1
Starting installing lamp...waiting...
LAMP is installed

注意:最常用的是中括号搭配 -gt -lt

4 、if 语句开发

单分支 if 语句

if	<条件表达式> 

	then

		代码

fi

简化:

if <条件表达式>;then

	代码...

fi

双分支 if语句

if <条件表达式>
	then 
		代码1...
		if <条件表达式>
			then
				代码2...
				...
		fi
fi	

伪代码编写

if <我有180w>
	then 
		"买车--"
		if<还剩100w>
			then
				"充值"
		fi
fi

if -else 处理

if <条件表达式>
	then
		当条件成立时,会执行。。
else
	否则会。。

多分支处理

if <条件表达式>
	then
		代码1
elif <t条件表达式2>
	then
		代码2
else
	代码3
fi

if 实践

  • 单分支
  • if分支的嵌套
  • 开发一个内存监控的脚本
  • 开发nginx,mysql服务监控脚本
  • 开发rsync起停脚本
  • 作业,nginx服务监控脚本

单分支

# 条件测试语句,改造为if判断语句,if结合条件测试

[root@localhost shell_program]# [ -f /etc/hosts ] && echo yes
yes
[root@localhost shell_program]# [[ -f /etc/hosts ]] && echo yes
yes
[root@localhost shell_program]# test -f /etc/hosts && echo yes
yes

# 改造为if脚本

#! /bin/bash

if [ -f /etc/hosts ] 
    then
        echo "[] is ok!"
fi

if  [[ -f /etc/hosts ]] ;then
    echo "[[]] is ok"
fi

if test -f /etc/hosts ;then
    echo "test is ok"
fi
 
开发系统监控脚本

开发脚本

1、检测linux剩余可用内存,当可用内存小于100M,就发邮件给运维

2、并且该脚本加入crontab,每3分钟检查一次内存

思路

1、获取当前内存情况

2、配置邮件警告,用linux发送邮件,邮件内容是内存剩余情况

3、开发脚本,获取内存情况

4、脚本加入crontab,写规则

开发过程

1、获取内存,获取available的数据,它是现实系统可以提供给应用程序 
free -m

[root@localhost test_scripts]# free -m
              total        used        free      shared  buff/cache   available
Mem:           3789         918        1644          83        1227        2424
Swap:          3967           0        3967
free -m | awk 'NR==2 {print $NF}'
2424

[root@localhost test_scripts]# crontab -l
*/3 * * * * /bin/bash /root/Desktop/sh/shell_program/test_scripts/freemem.sh &>/dev/null
#! /bin/bash

FreeMem=`free -m | awk 'NR==2 {print $NF}'`
CHARS="Current memory is $FreeMem"

if [ "$FreeMem" -lt 10000 ]
    then
        echo $CHARS|tee /root/Desktop/sh/shell_program/test_scripts/log.txt
        # mail -s "主题" 收件人 < 文件
        # mail -s "`date +%F-%T`$CHARS" 18756535536@163.com < /root/Desktop/sh/shell_program/test_scripts/log.txt
        echo "内存不足,维护"
        
fi
[root@localhost test_scripts]# crontab -l
*/3 * * * * /bin/bash /root/Desktop/sh/shell_program/test_scripts/freemem.sh &>/dev/null

# 加入定时任务的脚本。

实战脚本开发

#! /bin/bash

a=$1
b=$2

if [ "$a" -lt "$b" ];then
    echo "yes,$a less than $b"
    exit 0

elif [ "$a" -eq "$b" ];then 
    echo "yes,$a equal $b"
    exit 0
else
    echo "yes,$a grater than $b"
fi[root@localhost sh]# cat if_read.sh
#! /bin/bash

a=$1
b=$2

if [ "$a" -lt "$b" ]
    then
        echo "yes,$a less than $b"
        exit 0
fi

if [ "$a" -eq "$b" ]
    then
        echo "yes,$a equal $b"
    exit 0
fi

if [ "$a" -gt "$b" ]; then
    echo "yes,$a grater than $b"    
fi
[root@localhost sh]# bash if_read.sh 3 4
yes,3 less than 4
[root@localhost sh]# bash if_read.sh 2 2
yes,2 equal 2
[root@localhost sh]# bash if_read.sh 4 3
yes,4 grater than 3

#! /bin/bash

a=$1
b=$2

if [ "$a" -lt "$b" ];then
    echo "yes,$a less than $b"
    exit 0

elif [ "$a" -eq "$b" ];then 
    echo "yes,$a equal $b"
    exit 0
else
    echo "yes,$a grater than $b"
fi
开发 mysql 监控脚本

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5P5J8RKm-1692256124106)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230816095816897.png)]

端口监控,mysql的状态

[root@localhost sh]# netstat -tunlp | grep mysql | wc -l
1
[root@localhost sh]# ss -tunlp | grep mysql | wc -l
1
[root@localhost sh]# lsof -tunlp | grep mysql | wc -l
1

远程监控mysql端口

yum install telnet nmap nc -y
# nmap端口扫描
[root@localhost sh]# nmap 127.0.01 -p 3380 | grep open | wc -l  #查询是否存活
1

# Telnet
[root@localhost sh]# echo -e "\n" | telent 127.0.0.1 3380 >dev/null | grep Connected | wc - l

进程检查

[root@localhost sh]# ps -ef |grep mysql
root      2587 25132  0 10:48 pts/1    00:00:00 grep --color=auto mysql
[root@localhost sh]# ps -ef | grep mysql |grep -v grep
[root@localhost sh]# ps -ef | grep mysql |grep -v grep | wc -l
0

通过编程语言连接mysql

php程序

python程序

前提:准备好的mysql

<?php
    $mysql_id=mysql_connect("localhost","root","mw") or mysql_error();
if($mysql_id){
    echo "mysql connection succesful, 6"
}else{
    echo mysql_error();
}


# 1.安装python3依赖
# 2.通过python 的包管理工具

import pymysql

db = pymsql.connec(
	host = "localhost",
    port = 3380,
    user = "root",
    password = "chao",
    db = "mysql",
    charset = "utf8"
)

# 操控数据库

cursor = db.cursor()
cursor.execute("selecee version()")

data = cursor.fetchone()

print("数据库正确")

db.close()

检测mysql 的脚本方案

echo "----------方法1-----------"

if [ `netstat -tunlp | grep mysql | wc -l` = "1" ]; then
    echo "Mysql is running."
else
    echo "Mysql is stopped"
    systemctl start mysql
fi 


echo "----------方法2-----------"

if [ `ss -tunlp | grep mysql | wc -l` -eq "1" ]; then
    echo "Mysql is running."
else
    echo "Mysql is stopped"
    systemctl start mysql
fi 

echo "----------方法3-----------"


if [ `lsof -i tcp:3380 | wc -l` -gt "0" ]; then
    echo "Mysql is running."
else
    echo "Mysql is stopped"
    systemctl start mysql
fi 

echo "----------方法4-----------"

php /root/Desktop/sh/..


if [ `$?` = 0 ]; then
    echo "Mysql is running."
else
    echo "Mysql is stopped"
    systemctl start mysql
fi 
echo "----------方法5-----------"

php /root/Desktop/sh/..


if [ `$?` = 0 ]; then
    echo "Mysql is running."
else
    echo "Mysql is stopped"
    systemctl start mysql
fi 

echo "----------方法5-----------"

python3 /root/Desktop/sh/..


if [ `$?` = 0 ]; then
    echo "Mysql is running."
else
    echo "Mysql is stopped"
    systemctl start mysql
fi 

Rsync起停脚本开发
[root@localhost sh]# rpm -qa rsync
rsync-3.1.2-4.el7.x86_64
[root@localhost sh]# ls -l /etc/rsyncd.conf
-rw-r--r--. 1 root root 458 Apr 11  2018 /etc/rsyncd.conf
# 检查是否有rsyncd服务
[root@localhost sh]# netstat -tunlp | grep 873
[root@localhost sh]# /usr/bin/rsync --daemon
[root@localhost sh]# netstat -tunlp | grep 873
tcp        0      0 0.0.0.0:873             0.0.0.0:*               LISTEN      18968/rsync
tcp6       0      0 :::873                  :::*                    LISTEN      18968/rsync

#停止rsync服务
killall
pkill rsync

开发rsync 起停脚本

#! /bin/bash

# author:mw
# -ne if条件不等于,$# 返回传递给脚本的参数个数 $0 取得脚本文件名

if [ "$#" -ne "1" ]
    then 
        echo "Usage: $0 {start|stop|restart}"
        exit 1
fi

# 当用户选择启动rsync时

if [ "$1" = "start" ]
    then 
        /usr/bin/rsync --daemon
        sleep 2
        # 验证端口是否启动
        if [ `netstat -tunlp | grep rsync | wc -l ` -ge 1 ]
            then 
                echo "Rsync is started!"
                exit 0
        fi
        
elif [ "$1" = "stop" ]
    then
        killall rsync &>/dev/null
        sleep 2
        if [ `netstat -tunlp | grep rsync | wc -l ` -eq 0 ]
            then 
                echo "Rsync is stopped!"
                exit 0
        fi
        
elif [ "$1" = "restart" ]
    then
        killall rsync
        sleep 1
        killpro=`netstat -tunlp | grep rsync | wc -l `
        /usr/bin/rsync --daemon
        sleep 1
        startpro=`netstat -tunlp | grep rsync | wc -l `
        if [ "$killpro" -eq "0" -a "$startpro" -ge "1" ] 
            then
                echo "Rsync is restarted!"
                exit 0
        fi
else
    echo "Usage: $0 {start|stop|restart}"
    exit 1
fi
[root@localhost sh]# netstat -tunlp|grep 873
tcp        0      0 0.0.0.0:873             0.0.0.0:*               LISTEN      31892/rsync
tcp6       0      0 :::873                  :::*                    LISTEN      31892/rsync
[root@localhost sh]# sh rsync_control.sh stop
Rsync is stopped!
[root@localhost sh]# netstat -tunlp|grep 873
[root@localhost sh]# sh rsync_control.sh start
Rsync is started!
[root@localhost sh]# netstat -tunlp|grep 873
tcp        0      0 0.0.0.0:873             0.0.0.0:*               LISTEN      32261/rsync
tcp6       0      0 :::873                  :::*                    LISTEN      32261/rsync
[root@localhost sh]# sh rsync_control.sh restart
Rsync is restarted!
[root@localhost sh]# sh rsync_control.sh
Usage: rsync_control.sh {start|stop|restart}
[root@localhost sh]# sh rsync_control.sh sww
Usage: rsync_control.sh {start|stop|restart}

5、函数是什么?

[root@localhost sh]# alias
alias cp='cp -i'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
alias ls='ls --color=auto'
alias mv='mv -i'
alias perlll='eval `perl -Mlocal::lib`'
alias rm='rm -i'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'

shell函数开发

函数的特点,类似于alias别名一样,能够简化linux命令的操作,让整个命令更易读,更易用

  • 函数,就是将你需要执行的shell命令,组合起来,组合成一个函数体
  • 还得给函数体起一个名字,这个名字就称之为函数名
  • 函数名+函数体
  • 以后想执行函数,就使用函数名即可

使用函数的好处是什么?

shell函数的语法

# 简化版本的函数的定义与使用
# 定义函数,名字叫做sayhello()
# 花括号里面的是函数体,写入shell命令即可

sayHello()
{
	echo "大家好,才是真的好,广州好迪"
}

# 调用函数,执行函数
sayHello
  • 相同的程序,定义封装为一个函数,能够减少程序的代码数量,提高开发效率
  • 使用函数,能让你写更少的代码。
  • 函数能够增加程序的可读性,易读性,容器管理

shell函数实际开发

# 标准shell函数定义
function 函数名()
{
	函数体
	你想执行的Linux命令。。。
	return
}

# 函数先定义后执行
# 偷懒学法 
# 当使用function 关键字的时候,可以省略括号
function 函数名{
	函数体
	你想执行的Linux命令。。。
	return
}

# 超级懒人写法
函数名(){
	函数体
	你想执行的Linux命令。。。
	return
}

执行函数的基础概念

  • 有关函数执行的基础概念
  • 执行shell函数,直接写名字即可,无需添加其他内容
  • 函数必须先定义,在执行,shell脚本自上而下加载
  • 函数体内定义的变量,称之为局部变量
  • 函数体内需要添加return语句,作用是退出函数,且赋予返回值给调用该函数的程序,也就是shell脚本
    • return语句和exit不同
    • return是结束函数的执行,返回一个(退出值,返回值)
  • exit是结束shell环境,返回一个(退出值,返回值)给当前的shell
  • 函数如果单独写入一个文件里,需要用source读取(函数写入文件中,用于加载)
  • 函数内,使用local关键字,定义局部变量

函数实践

#! /bin/bash

chao()
{
	echo "我是函数,我被执行,你真棒"
}

# 如何检查当前shell环境变量
set |grep 需要找的变量
# 3.利用或者source命令读取shell脚本,能够加载其变量到当前的shell环境中
source my_func.sh   ->加载到环境中
# 4.继续查找是否添加到环境变量中
set | grep ^变量
# 5.退出变量消失
# 再加上source 加入到shell环境变量中

source和bash 是否开启子进程

函数脚本传入参数


#! /bin/bash/

[ -f /root/Desktop/sh/fun_arg.sh ] && . /root/Desktop/sh/fun_arg.sh || exit



helloPyyu $1 $2 $3
#! /bin/bash/

chao()
{
    echo "this is a function"
}


helloPyyu()
{
    echo "你传入的脚本参数,依次为:$1,$2,$3,并且传入的参数个数一共为$#"
    
}


函数实战开发

检测url是否正常,要求是函数开发形式
#  非函数版本
#! /bin/bash/

if [ "$#" -ne 1 ]
    then
        echo "Usage:$0 url"
        exit 1
fi

# 利用weget命令测试url 是否正常
wget --spider -q -o /dev/null --tries=1 -T 5 $1


# 对状态码判读 网站是否正常

if [ "$?" -eq 0 ]
    then
        echo "$1 is running"
else
    echo "$1 is down"
    
fi
#! /bin/bash/

function usage(){
    echo "Usage:$0 url"
    exit 1
 
}


check_url()
{
    # 利用weget命令测试url 是否正常
    wget --spider -q -o /dev/null --tries=1 -T 5 $
    
    # 对状态码判读 网站是否正常
    
    if [ "$?" -eq 0 ]
        then
            echo "$1 is running"
    else
        echo "$1 is down"
        
    fi
}

# 参考C语言开发

main()
{
  if [ "$#" -ne 1 ]
        then
            usage
  fi
  
  
    check_url $1
}


main $*

美化脚本

lsb_functions="/lib/lsb/init-functions"
if test -f $lsb_functions ; then
  . $lsb_functions
else
  log_success_msg()
  {
    echo " SUCCESS! $@"
  }
  log_failure_msg()
  {
    echo " ERROR! $@"
  }
fi
开发rsync管理脚本
#! /bin/bash

lsb_functions="/lib/lsb/init-functions"
if test -f $lsb_functions ; then
  . $lsb_functions
else
  log_success_msg()
  {
    echo " SUCCESS! $@"
  }
  log_failure_msg()
  {
    echo " ERROR! $@"
  }
fi



Shell好用的工具: cut

目标

使用cut可以切割提取指定列\字符\字节的数据

介绍

cut 译为“剪切, 切割” , 是一个强大文本处理工具,它可以将文本按列进行划分的文本处理。cut命令逐行读入文本,然后按列划分字段并进行提取、输出等操作。

语法

cut [options]  filename

options参数说明

选项参数功能
-f 提取范围列号,获取第几列
-d 自定义分隔符自定义分隔符,默认为制表符。
-c 提取范围以字符为单位进行分割
-b 提取范围以字节为单位进行分割。这些字节位置将忽略多字节字符边界,除非也指定了 -n 标志。
-n与“-b”选项连用,不分割多字节字符;

提取范围说明

提取范围说明
n-提取指定第n列或字符或字节后面所有数据
n-m提取指定第n列或字符或字节到第m列或字符或字节中间的所有数据
-m提取指定第m列或字符或字节前面所有数据
n1,n2,…提前指定枚举列的所有数据

示例:切割提取指定列数据

cut1.txt文件数据准备

touch cut1.txt

编辑文件添加内容

AA  itheima 11 XX
BB  itcast 22 XXX
CC  Shell 33 XXXX
DD  it 44 XXXXXXX

提取文件中第一列数据

cut cut1.txt -d " " -f 1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bo73nk0O-1692256124107)(E:/学习资料/shell/第四天/笔记/assets/image-20200707230710596.png)]

提取文件中第一列,第三列, 枚举查找

cut cut1.txt -d " " -f 1,3

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ERMuiiTR-1692256124108)(E:/学习资料/shell/第四天/笔记/assets/image-20200707232926482.png)]

提取文件中第二列,第三列,第四列, 范围查找

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tvJe2wHg-1692256124108)(E:/学习资料/shell/第四天/笔记/assets/image-20200707233024564.png)]

提取文件中第一列后面所有列的数据

 cut cut1.txt -d " "  -f 2- 

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a99OVi5n-1692256124108)(E:/学习资料/shell/第四天/笔记/assets/image-20200709220852618.png)]

提起文件中结束列前面所有列的数据

cut -d " " -f -2 cut1.txt
# -2 提取指定列前面所有列数据

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i96CoYbK-1692256124109)(E:/学习资料/shell/第四天/笔记/assets/image-20200711142437017.png)]

示例: 切割提取指定字符数据

提取每行前3个字符

cut cut1.txt -c1-3

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-drY3IH5l-1692256124109)(E:/学习资料/shell/第四天/笔记/assets/image-20200711142653293.png)]

提取每行第4个字符以后的数据

cut cut1.txt -c 4-

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-id76mkMl-1692256124109)(E:/学习资料/shell/第四天/笔记/assets/image-20200711143324756.png)]

提取每行第3个字符前面所有字符

cut cut1.txt -c -3

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BV5mpdPj-1692256124113)(E:/学习资料/shell/第四天/笔记/assets/image-20200711143438631.png)]

示例:切割提取指定字节数据

提取字符串"abc传智播客" 前3个字节

echo "abc传智播客" | cut -b -3

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dMRuS5QN-1692256124114)(E:/学习资料/shell/第四天/笔记/assets/image-20200711143706340.png)]

提取字符串"abc传智播客" 前4个字节

echo "abc传智播客" | cut -b -4

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d074e7DY-1692256124114)(E:/学习资料/shell/第四天/笔记/assets/image-20200711143754196.png)]

提取字符串"abc传智播客" 前6个字节

echo "abc传智播客" | cut -b -6
# 由于linux系统默认utf-8码表, 所以一个汉字占3个字节

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OOiIWK4p-1692256124114)(E:/学习资料/shell/第四天/笔记/assets/image-20200711143926461.png)]

提取字符串"abc传智播客" 前4个字节, 就可以将汉字 "传"输出,

echo "abc传智播客" | cut -nb -4
#  -n 取消多字节字符分割直接输出

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6iZ8FMzW-1692256124114)(E:/学习资料/shell/第四天/笔记/assets/image-20200711144139142.png)]

示例:切割提取指定单词数据

在cut1.txt文件中切割出"itheima"

cat cut1.txt | grep itheima | cut -d " " -f 2

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8kvem044-1692256124115)(E:/学习资料/shell/第四天/笔记/assets/image-20200708003059162.png)]

示例:切割提取bash进程的PID号

命令

ps -aux | grep 'bash' | head -n 1 | cut -d " " -f 8

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GL5XNuFB-1692256124115)(E:/学习资料/shell/第四天/笔记/assets/image-20200711120636232.png)]

示例:切割提取IP地址

ifconfig | grep broadcast | cut -d " " -f 10

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ma6fiEV1-1692256124115)(E:/学习资料/shell/第四天/笔记/assets/image-20200711115310554.png)]

小结

cut的作用

一个强大文本处理工具,它可以将文本按列进行划分的文本处理。cut命令逐行读入文本,然后按列划分字段并进行提取、输出等操作。

cut切割提取列

cut 文件或数据 -d 分隔符切割 -f 提取第X列

cut切割提取字符

cut 文件或数据 -c 提取字符范围

cut切割提取字节

cut 文件或数据 -nb 提取直接范围

Shell好用的工具:sed

目标

使用sed编辑文件替换文件中的单词

编写在文件中插入或修改行的sed程序

使用sed作为过滤器来过滤管道数据命令

介绍

sed (stream editor, 流编辑器) 是Linux下一款功能强大的非交互流式文本编辑器(vim是交互式文本编辑器),可以对文本文件的每一行数据匹配查询之后进行增、删、改、查等操作,支持按行、按字段、按正则匹配文本内容,灵活方便,特别适合于大文件的编辑.

sed是一种流编辑器,它一次处理一行内容, 将这行放入缓存(存区空间称为:模式空间),然后才对这行进行处理,处理完后,将缓存区的内容发送到终端。

sed处理数据原理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N6A2xo1C-1692256124116)(E:/学习资料/shell/第四天/笔记/assets/image-20200711095515087.png)]

语法

sed [选项参数] [模式匹配/sed程序命令] [文件名]

# 模式匹配,sed会读取每一行数据到模式空间中, 之后判断当前行是否符合模式匹配要求,符合要求就会
#     执行sed程序命令, 否则不会执行sed程序命令;如果不写匹配模式,那么每一行都会执行sex程序命令

选项参数说明

选项参数功能
-e直接在指令列模式上进行sed的动作编辑。它告诉sed将下一个参数解释为一个sed指令,只有当命令行上给出多个sed指令时才需要使用-e选项;一行命令语句可以执行多条sed命令
-i直接对内容进行修改,不加-i时默认只是预览,不会对文件做实际修改
-f后跟保存了sed指令的文件
-n取消默认输出,sed默认会输出所有文本内容,使用-n参数后只显示处理过的行
-r ruguler 使用扩展正则表达式,默认情况sed只识别基本正则表达式 *

sed程序命令功能描述

命令功能描述
aadd新增,a的后面可以接字串,在下一行出现
cchange更改, 更改匹配行的内容
ddelete删除, 删除匹配的内容
iinsert插入, 向匹配行前插入内容
pprint打印, 打印出匹配的内容,通常与-n选项和用
ssubstitute替换, 替换掉匹配的内容
=用来打印被匹配的行的行号
n读取下一行,遇到n时会自动跳入下一行

特殊符号

命令功能描述
!就像一个sed命令,放在限制条件后面, 对指定行以外的所有行应用命令(取反)
{sed命令1;sed命令2}多个命令操作同一个的行

数据准备

sed.txt文件内容

ABC
itheima itheima
itcast
123
itheima

示例:向文件中添加数据

演示1: 指定行号的前或后面添加数据

向第三行后面添加hello

 sed '3ahello' sed.txt

3 , 代表第三行

a, 代表在后面添加, 出现在下一行

注意这里没有修改源文件

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-acgUhfPm-1692256124116)(E:/学习资料/shell/第四天/笔记/assets/image-20200710000018446.png)]

向第三行前面添加hello

 sed '3ihello' sed.txt

3 , 代表第三行

i, 代表在前面添加, 出现在上一行

注意这里没有修改源文件

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TeJbOlLo-1692256124116)(E:/学习资料/shell/第四天/笔记/assets/image-20200710000824539.png)]

演示2: 指定内容前或后面添加数据

向内容 itheima 后面添加 hello ,如果文件中有多行包括 ``itheima ,则每一行后面都会添加

sed '/itheima/ahello' sed.txt

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zjmIsYmh-1692256124116)(E:/学习资料/shell/第四天/笔记/assets/image-20200710000117275.png)]

向内容 itheima 前面添加 hello ,如果文件中有多行包括 ``itheima ,则每一行前面都会添加

sed '/itheima/ihello' sed.txt

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-woJS283N-1692256124117)(E:/学习资料/shell/第四天/笔记/assets/image-20200710001012028.png)]

演示3: 在最后一行前或后添加hello

在最后一行后面添加hello

sed '$ahello' sed.txt

$a: 最后一行后面添加

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MNh65BCu-1692256124117)(E:/学习资料/shell/第四天/笔记/assets/image-20200710000330765.png)]

在最后一行前面添加hello

sed '$ihello' sed.txt

$i: 最后一行前面添加

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0uP1doKl-1692256124117)(E:/学习资料/shell/第四天/笔记/assets/image-20200710001219163.png)]

示例: 删除文件中的数据

演示1: 删除第2行

命令

sed  '2d' sed.txt
# d 用于删除
# 2d 删除第2行

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1hepXlfu-1692256124118)(E:/学习资料/shell/第四天/笔记/assets/image-20200710165604688.png)]

命令: 删除第1行,第4行数据

sed '1d;4d' sed.txt

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d9dQtbwk-1692256124118)(E:/学习资料/shell/第四天/笔记/assets/image-20200711112046339.png)]

演示2: 删除奇数行

从第一行开始删除,每隔2行就删掉一行

sed '1~2d' sed.txt
# 1~2 从第1行开始, 每隔2行

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L4viOkUm-1692256124118)(E:/学习资料/shell/第四天/笔记/assets/image-20200710170036140.png)]

演示3: 删除指定范围的多行数据

删除从第1行到第3行的数据

sed '1,3d' sed.txt
# 1,3  从指定第1行开始到第3行结束

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gXDuWZdr-1692256124119)(E:/学习资料/shell/第四天/笔记/assets/image-20200710170338110.png)]

演示3: 删除指定范围取反的多行数据

删除从第1行到第3行取反的数据

sed '1,3!d' sed.txt
# 1,3! 从指定第1行开始到第3行结束取反, 就是不在这个范围的行

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kkch52jW-1692256124119)(E:/学习资料/shell/第四天/笔记/assets/image-20200710171410645.png)]

演示4: 删除最后一行

命令

sed  '$d'   sed.txt

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9xR4alWS-1692256124119)(E:/学习资料/shell/第四天/笔记/assets/image-20200710173137962.png)]

演示5: 删除匹配itheima的行

命令

sed '/itheima/d' sed.txt

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-10Y7Mk4v-1692256124119)(E:/学习资料/shell/第四天/笔记/assets/image-20200710173601573.png)]

演示6: 删除匹配行到最后一行

删除匹配itheima行到最后一行 , 命令

sed '/itheima/,$d' sed.txt
# , 代表范围匹配

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vKdlsvpp-1692256124120)(E:/学习资料/shell/第四天/笔记/assets/image-20200710174149348.png)]

演示7: 删除匹配行及其后面一行

删除匹配itheima行及其后面一行

sed '/itheima/,+1d' sed.txt

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vb2KfiXC-1692256124120)(E:/学习资料/shell/第四天/笔记/assets/image-20200710174655691.png)]

演示9: 删除不匹配的行

删除不匹配 itheimaitcast 的行

sed '/itheima\|itcast/!d' sed.txt

# \| 是正则表达式的或者 这里|需要转义, 所以为\|
# ! 取反

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fsB3TkkT-1692256124120)(E:/学习资料/shell/第四天/笔记/assets/image-20200711105205862.png)]

示例:更改文件中的数据

演示1:将文件的第一行修改为hello

命令

sed  '1chello'  sed.txt

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z8xvY9Ti-1692256124120)(E:/学习资料/shell/第四天/笔记/assets/image-20200710110433788.png)]

演示2: 将包含itheima的行修改为hello

命令

sed  '/itheima/chello' sed.txt

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mjkg2Mcz-1692256124121)(E:/学习资料/shell/第四天/笔记/assets/image-20200710110651523.png)]

演示3: 将最后一行修改为hello

命令

sed '$chello' sed.txt

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MMKRqvS8-1692256124121)(E:/学习资料/shell/第四天/笔记/assets/image-20200710111014651.png)]

演示4: 将文件中的itheima替换为hello

将文件中的itheima替换为hello,默认只替换每行第一个itheima

sed 's/itheima/hello/'  sed.txt

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7ZEn3FXv-1692256124121)(E:/学习资料/shell/第四天/笔记/assets/image-20200710154359291.png)]

注意 's/itheima/hello/' 最后一个/ 不可少

将文本中所有的itheima都替换为hello, 全局替换

sed 's/itheima/hello/g'  sed.txt
# g 代表匹配全局所有符合的字符

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9860pJve-1692256124121)(E:/学习资料/shell/第四天/笔记/assets/image-20200710154642832.png)]

演示5: 将每行中第二个匹配替换

将每行中第二个匹配的itheima替换为hello 命令

sed 's/itheima/hello/2'   sex.txt

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qtAVZnRT-1692256124122)(E:/学习资料/shell/第四天/笔记/assets/image-20200710154829235.png)]

演示6: 替换后的内容写入文件

将每行中第二个匹配的itheima替换为hello , 将替换后的内容写入到sed2.txt文件中

# 第一种方式
sed -n 's/itheima/hello/2pw sed2.txt' sed.txt
# w写入
# p打印, -n只是获取

# 第二种方式
sed -n 's/itheima/hello/2p ' sed.txt > sed2.txt

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j1ahe0Lt-1692256124122)(E:/学习资料/shell/第四天/笔记/assets/image-20200710161127555.png)]

演示7: 正则表达式匹配替换

匹配有 i 的行,替换匹配行中 t 后的所有内容为空

sed '/i/s/t.*//g' sed.txt
# /t.*/ 表示逗号后的所又内容

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ItFkrkkh-1692256124122)(E:/学习资料/shell/第四天/笔记/assets/image-20200710162013813.png)]

演示8: 每行末尾拼接test

sed 's/$/& test' sed.txt
# & 用于拼接

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UTo3iJbZ-1692256124123)(E:/学习资料/shell/第四天/笔记/assets/image-20200710164435499.png)]

演示9: 每行行首添加注释 #

命令

sed 's/^/#/' sed.txt

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HO9RPefk-1692256124123)(E:/学习资料/shell/第四天/笔记/assets/image-20200711111533278.png)]

示例: 查询文件或管道中的数据

需求1: 查询含有 itcast 的行数据

命令

sed -n '/itcast/p' sed.txt

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jCk8pJ62-1692256124123)(E:/学习资料/shell/第四天/笔记/assets/image-20200711113348831.png)]

需求2: 管道过滤查询

管道查询所有进程中含有sshd的进程信息命令

 ps -aux | sed -n '/sshd/p'

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d3qJLS8H-1692256124124)(E:/学习资料/shell/第四天/笔记/assets/image-20200711113226364.png)]

示例: 多个sed程序命令执行

将sed.txt文件中的第1行删除并将 itheima 替换为 itcast

# 第一种方式, 多个sed程序命令 在每个命令之前使用 -e 参数
sed -e '1d' -e 's/itheima/itcast/g' sed.txt 

# 第二种方式
sed  '1d;s/itheima/itcast/g' sed.txt

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-prkZHLVd-1692256124124)(E:/学习资料/shell/第四天/笔记/assets/image-20200711105707546.png)]

sed高级用法: 缓存区数据交换

模式空间与暂存空间介绍

  1. 首先需要明白, sed处理文件是逐行处理的, 即读取一行处理一行,输出一行;

  2. sed把文件读出来每一行存放的空间叫模式空间, 会在该空间中对读到的内容做相应处理;

  3. 此外sed还有一个额外的空间即暂存空间, 暂存空间刚开始里边只有个空行, 记住这一点;

  4. sed可使用相应的命令从模式空间往暂存空间放入内容或从暂存空间取内容放入模式空间;

    2个缓存空间传输数据的目的是为了更好的处理数据, 一会参考案例学习

关于缓存区sed程度命令

命令含义
h模式空间里面的内容复制到暂存空间缓存区(覆盖方式)
H模式空间里面的内容复制到暂存空间缓存区(追加方式)
g暂存空间里面的内容复制到模式空间缓存区(覆盖方式)
G暂存空间里面的内容复制到模式空间缓存区(追加方式)
x交换2个空间的内容

示例: 缓存空间数据交换

演示1: 第一行粘贴到最后1行

将模式空间第一行复制到暂存空间(覆盖方式),并将暂存空间的内容复制到模式空间中的最后一行(追加方式)

sed '1h;$G' sed.txt
# 1h 从模式空间中将第一行数据复制到暂存空间(覆盖方式)
# $G 将暂存空间中的内容复制到模式空间中最后一行(追加方式)

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qomgOHcF-1692256124124)(E:/学习资料/shell/第四天/笔记/assets/image-20200711103556835.png)]

演示2: 第一行删除后粘贴到最后1行

将模式空间第一行复制到暂存空间(覆盖方式)并删除, 最后将暂存空间的内容复制到模式空间中的最后一行(追加方式)

sed '1{h;d};$G' sed.txt
# 1{h;d}对模式空间中的第一行数据同时进行复制到暂存空间(覆盖方式)和删除模式空间中的第一行数据

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nI11nt3N-1692256124124)(E:/学习资料/shell/第四天/笔记/assets/image-20200711103901519.png)]

演示3: 第一行数据复制粘贴替换其他行数据

将模式空间第一行复制到暂存空间(覆盖方式), 最后将暂存空间的内容复制到模式空间中替换从第2行开始到最后一行的每一行数据(覆盖方式)

sed '1h;2,$g' sed.txt

运行命令

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-APwwv08j-1692256124125)(E:/学习资料/shell/第四天/笔记/assets/image-20200711104451987.png)]

演示4: 将前3行数据数据复制粘贴到最后一行

将前3行数据复制到暂存空间(追加方式), 之后将暂存空间的所有内容复制粘贴到模式空间最后一行(追加方式)

sed '1,3H;$G' sed.txt

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LqT3nm8y-1692256124125)(E:/学习资料/shell/第四天/笔记/assets/image-20200711104856968.png)]

示例: 给每一行添加空行

插入空行

sed G -i sed.txt
# G 每行后面添加一个空行
# -i 修改源文件

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EqJE26fN-1692256124125)(E:/学习资料/shell/第四天/笔记/assets/image-20200711095724616.png)]

示例: 删除所有的空行

命令

sed -i '/^$/d' sed.txt

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VNOLLGxa-1692256124125)(E:/学习资料/shell/第四天/笔记/assets/image-20200711095844232.png)]

Shell好用的工具:awk

介绍

awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理, 因为切开的部分使用awk可以定义变量,运算符, 使用流程控制语句进行深度加工与分析。

创始人 Alfred V. Aho、Peter J. Weinberger和Brian W. Kernighan awk由来是姓氏的首字母

语法

awk [options] 'pattern{action}' {filenames}

pattern:表示AWK在数据中查找的内容,就是匹配模式

action:在找到匹配内容时所执行的一系列命令

选项参数说明

选项参数功能
-F指定输入文件拆分分隔符
-v赋值一个用户定义变量

awk内置变量

内置变量含义
ARGC命令行参数个数
ARGV命令行参数排列
ENVIRON支持队列中系统环境变量的使用
FILENAMEawk浏览的文件名
FNR浏览文件的记录数
FS设置输入域分隔符,等价于命令行 -F选项
NF浏览记录的域的个数, 根据分隔符分割后的列数
NR已读的记录数, 也是行号
OFS输出域分隔符
ORS输出记录分隔符
RS控制记录分隔符
$n$0变量是指整条记录。$1表示当前行的第一个域,$2表示当前行的第二个域,…以此类推。
$NF$NF是number finally,表示最后一列的信息,跟变量NF是有区别的,变量NF统计的是每行列的总数

数据准备

cp /etc/passwd ./

示例 : 默认每行空格切割数据

命令

 echo "abc 123 456" | awk '{print $1"&"$2"&"$3}'

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U4tgZrVA-1692256124126)(E:/学习资料/shell/第四天/笔记/assets/image-20200712145458252.png)]

示例: 打印含有匹配信息的行

搜索passwd文件有root关键字的所有行

awk '/root/' passwd
# '/root/' 是查找匹配模式, 没有action命令, 默认输出所有符合的行数据

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LsjcjoAV-1692256124126)(E:/学习资料/shell/第四天/笔记/assets/image-20200711163917949.png)]

示例: 打印匹配行中第7列数据

搜索passwd文件有root关键字的所有行, 然后以":"拆分并打印输出第7列

awk -F: '/root/{print $7}' passwd
# -F: 以':'分隔符拆分每一个列(域)数据

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CjulceRY-1692256124126)(E:/学习资料/shell/第四天/笔记/assets/image-20200711164512294.png)]

示例: 打印文件每行属性信息

统计passwd: 文件名,每行的行号,每行的列数,对应的完整行内容:

awk -F ':' '{print "文件名:" FILENAME ",行号:" NR ",列数:" NF ",内容:" $0}' passwd
# "文件名:" 用于拼接字符串

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wvr3S30I-1692256124127)(E:/学习资料/shell/第四天/笔记/assets/image-20200711165433352.png)]

使用printf替代print,可以让代码阅读型更好

awk -F ':' '{printf("文件名:%5s,行号:%2s, 列数:%1s, 内容:%2s\n",FILENAME,NR,NF,$O)}' passwd
# printf(格式字符串,变量1,变量2,...)
# 格式字符串: %ns 输出字符串,n 是数字,指代输出几个字符, n不指定自动占长度
# 格式字符串: %ni 输出整数,n 是数字,指代输出几个数字
# 格式字符串: %m.nf 输出浮点数,m 和 n 是数字,指代输出的整数位数和小数位数。如 %8.2f 代表共输出 8 位数,其中 2 位是小数,6 位是整数;

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WFBK75Sy-1692256124127)(E:/学习资料/shell/第四天/笔记/assets/image-20200711170720468.png)]

示例: 打印第二行信息

打印/etc/passwd/的第二行信息

awk -F ':' 'NR==2{printf("filename:%s,%s\n",FILENAME,$0)}' passwd

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a88JPXOo-1692256124128)(E:/学习资料/shell/第四天/笔记/assets/image-20200711171311183.png)]

示例: 查找以c开头的资源

awk过滤的使用, 查找当前目录下文件名以c开头的文件列表

ls -a | awk '/^c/'

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nb5KCCRr-1692256124128)(E:/学习资料/shell/第四天/笔记/assets/image-20200711171918200.png)]

示例: 打印第一列

按照":" 分割查询第一列打印输出

awk -F ':' '{print $1}' passwd

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Yz3bD91d-1692256124128)(E:/学习资料/shell/第四天/笔记/assets/image-20200711172121503.png)]

示例: 打印最后1列

按照":" 分割查询最后一列打印输出

awk -F: '{print $NF}' passwd

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lVMFkSJO-1692256124128)(E:/学习资料/shell/第四天/笔记/assets/image-20200711172417497.png)]

示例: 打印倒数第二列

按照":" 分割查询倒数第二列打印输出

 awk -F: '{print $(NF-1)}' passwd
 # $(NF-N) N是几, 就是倒数第几列

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1c0FEyzp-1692256124129)(E:/学习资料/shell/第四天/笔记/assets/image-20200711173518580.png)]

示例: 打印10到20行的第一列

获取第10到20行的第一列的信息

awk -F: '{if(NR>=10 && NR<=20) print $1}' passwd

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3m9wKBn2-1692256124129)(E:/学习资料/shell/第四天/笔记/assets/image-20200711173734821.png)]

示例: 多分隔符使用

“one:two/three"字符串按照多个分隔符”:“或者”/" 分割, 并打印分割后每个列数据

echo "one:two/three" | awk -F '[:/]' '{printf("%s\n%s\n%s\n%s\n",$0,$1,$2,$3)}'

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1wWSKbJn-1692256124129)(E:/学习资料/shell/第四天/笔记/assets/image-20200711174827654.png)]

示例: 添加开始与结束内容

给数据添加开始与结束

echo -e  "abc\nabc" | awk 'BEGIN{print "开始..."} {print $0} END{print "结束..."}'

# BEGIN 在所有数据读取行之前执行;END 在所有数据执行之后执行。

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WPCVM3K4-1692256124129)(E:/学习资料/shell/第四天/笔记/assets/image-20200711181845642.png)]

示例 : 使用循环拼接分割后的字符串

“abc itheima itcast 21” 使用空格分割后, 通过循环拼接在一起

 echo "abc itheima     itcast   21" | awk -v str="" -F '[ ]+' '{for(n=1;n<=NF;n++){ str=str$n} print str }'
 
 # -v 定义变量

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Duhbz84H-1692256124130)(E:/学习资料/shell/第四天/笔记/assets/image-20200711213649299.png)]

示例: 操作指定数字运算

将passwd文件中的用户id增加数值1并输出

 echo "2.1" | awk -v i=1 '{print $0+i}'

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WpJrmtnp-1692256124130)(E:/学习资料/shell/第四天/笔记/assets/image-20200711215839824.png)]

示例: 切割ip

切割IP

ifconfig | awk '/broadcast/{print}' | awk -F " " '{print $2}'

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6twnCYBt-1692256124130)(E:/学习资料/shell/第四天/笔记/assets/image-20200711220230406.png)]

示例: 显示空行行号

查询sed.txt中空行所在的行号

sed 'G' sed.txt | awk '/^$/{print NR}'

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yiUKxXFE-1692256124130)(E:/学习资料/shell/第四天/笔记/assets/image-20200712085616584.png)]

小结

grep , sed ,awk , cut 文本字符串操作四剑客的区别

grep:用于查找匹配的行

cut: 截取数据. 截取某个文件中的列, 重点是按照列分割, 这个命令不适合截取文件中有多个空白字符的字段

sed: 增删改查数据. sed用于在文件中以行来截取数据进行增\删\改\查

awk:截取分析数据. 可以在某个文件中是以竖列来截取分析数据, 如果字段之间含有很多空白字符也可以获取需要的数据, awk是一种语言,可以深入分析文件数据

Shell好用的工具:sort

目标

能够使用sort对字符串升序或降序排序

能够使用sort 对数字升序或降序

能够使用sort 对多列进行排序

介绍

sort命令是在Linux里非常有用,它将文件进行排序,并将排序结果标准输出或重定向输出到指定文件。

语法

sort (options) 参数
选项说明
-nnumber,依照数值的大小排序
-rreverse, 以相反的顺序来排序
-t 分隔字符设置排序时所用的分隔字符, 默认空格是分隔符
-k指定需要排序的列
-d排序时,处理英文字母、数字及空格字符外,忽略其他的字符。
-f排序时,将小写字母视为大写字母
-b忽略每行前面开始出的空格字符
-o 输出文件将排序后的结果存入指定的文件
-u意味着是唯一的(unique),输出的结果是去完重了的
-m将几个排序好的文件进行合并

参数:指定待排序的文件列表

数据准备

sort.txt文本文件代码

张三 30  
李四 95  
播仔 85 
播仔 85
播仔 86
AA 85
播妞 100

示例1: 数字升序

按照“ ”空格分割后的第2列数字升序排序。

sort -t " " -k2n,2 sort.txt
# -t " " 代表使用空格分隔符拆分列
# -k 2n,2 代表根据从第2列开始到第2列结束进行数字升序, 仅对第2列排序

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bjRVeymu-1692256124131)(E:/学习资料/shell/第四天/笔记/assets/image-20200713012421583.png)]

示例2: 数字升序去重

先按照“ ”空格分割后的, 然后,按照第2列数字升序排序, 最后对所有列去重

 sort -t " " -k2n,2 -uk1,2 sort.txt

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LdRk68X2-1692256124131)(E:/学习资料/shell/第四天/笔记/assets/image-20200713012712536.png)]

注意: 先排序再去重

示例3: 数字升序去重结果保存到文件

命令

sort -t " " -k2n,2 -uk1,2 -o sort2.txt sort.txt

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-opQjnthS-1692256124131)(E:/学习资料/shell/第四天/笔记/assets/image-20200713012900639.png)]

示例4: 数字降序去重

先按照“ ”空格分割后的, 然后,按照第2列数字降序排序, 最后对所有列去重

sort -t " " -k2nr,2 -uk1,2 sort.txt

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wdue3rb2-1692256124131)(E:/学习资料/shell/第四天/笔记/assets/image-20200713013216947.png)]

示例5: 多列排序

数据准备sort3.txt

公司A,部门A,3
公司A,部门B,0
公司A,部门C,10
公司A,部门D,9
公司B,部门A,30
公司B,部门B,40
公司B,部门C,43
公司B,部门D,1
公司C,部门A,30
公司C,部门B,9
公司C,部门C,100
公司C,部门D,80
公司C,部门E,60

要求: 以","分割先对第一列字符串升序, 再对第3列数字降序

sort -t "," -k1,1 -k3nr,3 sort3.txt

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LVyclpwk-1692256124132)(E:/学习资料/shell/第四天/笔记/assets/image-20200713013821197.png)]

小结

能够使用sort对字符串升序或降序排序

字符串升序: sort -kstart,end 文件

字符串降序: sort -kstartr,end 文件

能够使用sort 对数字升序或降序

数字升序: sort -kstartn,end 文件

数字降序: sort -kstartnr,end 文件

能够使用sort 对多列进行排序

sort -kstart[nr],end -kstart[nr],end ... 文件

面试题:查空行

问题:使用Linux命令查询file.txt中空行所在的行号

file1.txt数据准备

itheima itheima

itcast
123

itheima

答案:

awk '/^$/{print NR}' file1.txt

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XrtQ2GTT-1692256124132)(E:/学习资料/shell/第四天/笔记/assets/image-20200713081907537.png)]

面试题:求一列的和

问题:有文件file2.txt内容如下:

张三 40
李四 50
王五 60

使用Linux命令计算第二列的和并输出

awk '{sum+=$2} END{print "求和: "sum}' file2.txt

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CvtHtD7Q-1692256124133)(E:/学习资料/shell/第四天/笔记/assets/image-20200713082237986.png)]

面试题:检查文件是否存在

问题:Shell脚本里如何检查一个文件是否存在?如果不存在该如何处理?

答:

if [ -e /root/file1.txt ]; then  echo "文件存在"; else echo "文件不存在"; fi

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K9Cv9mr3-1692256124133)(E:/学习资料/shell/第四天/笔记/assets/image-20200713082603013.png)]

面试题:数字排序

问题:用shell写一个脚本,对文本中无序的一列数字排序

cat file3.txt文件内容

9
8
7
6
5
4
3
2
10
1

sort -n file3.txt | awk '{sum+=$1; print $1} END{print "求和: "sum}'

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ENZvM2wX-1692256124133)(E:/学习资料/shell/第四天/笔记/assets/image-20200713083045742.png)]

面试题:搜索指定目录下文件内容

问题:请用shell脚本写出查找当前文件夹(/root)下所有的文本文件内容中包含有字符”123”的文件名称?

答:

grep -r "123" /root | cut -d ":" -f 1| sort -u

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q7APEOjF-1692256124134)(E:/学习资料/shell/第四天/笔记/assets/image-20200713083912322.png)]

面试题:批量生成文件名

问题: 批量生产指定数目的文件,文件名采用"纳秒"命名

答: file4.sh

#!/bin/bash
read -t 30 -p "请输入创建文件的数目:" n
test=$(echo $n | sed 's/[0-9]//g') #检测非数字输入
if [ -n "$n" -a -z "$test" ] #检测空输入
then
        for ((i=0;i<$n;i=i+1 ))
        do
                name=$(date +%N)
                [ ! -d ./temp ] &&  mkdir -p ./temp
                touch "./temp/$name"
                echo "创建 $name 成功!"
        done
        else
                echo "创建失败"
                exit 1
fi

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bcy0BkxO-1692256124134)(E:/学习资料/shell/第四天/笔记/assets/image-20200713085107848.png)]

面试题:批量改名

问题: 将/root/temp目录下所有文件名重命名为"旧文件名-递增数字"?

重命名命令

rename 旧文件名 新文件名 旧文件所在位置

脚本代码file5.sh

#!/bin/bash
filenames=$(ls /root/temp)
number=1
for name in $filenames
do
        printf "命令前:%s" ${name}
        newname=${name}"-"${number}
        rename $name ${newname} /root/temp/*
        let number++ #每个改名后的文件名后缀数字加1
        printf "重命名后:%s \n" ${newname}
done

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-36k7LTGa-1692256124134)(E:/学习资料/shell/第四天/笔记/assets/image-20200713091236973.png)]

面试题:批量创建用户

问题: 根据users.txt中提供的用户列表,一个名一行, 批量添加用户到linux系统中

已知users.txt数据准备

user1
user2

知识点分析1: 添加用户命令

useradd 用户名

知识点分析2: 设置每个用户密码默认密码

echo "123456" | passwd --stdin 用户名

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qhzYk9pG-1692256124135)(E:/学习资料/shell/第四天/笔记/assets/image-20200713092318381.png)]

面试题答案: 脚本代码file6.sh

#!/bin/bash
ULIST=$(cat /root/users.txt)  ##/root/users.txt  里面存放的是用户名,一个名一行
for UNAME in $ULIST
do
        useradd $UNAME
        echo "123456" | passwd --stdin $UNAME &>/dev/null
        [ $? -eq 0 ] && echo "$UNAME用户名与密码添加初始化成功!"
done

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4WUMAeq8-1692256124135)(E:/学习资料/shell/第四天/笔记/assets/image-20200713093129265.png)]

面试题:筛选单词

问题: 根据给出的数据输出里面单词长度大于3的单词

数据准备

I may not be able to change the past, but I can learn from it.

shell脚本file7.sh

 echo "I may not be able to change the past, but I can learn from it." | awk -F "[ ,.]" '{for(i=1;i<NF;i++){ if(length($i)>3){print $i}}}'

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qaiB16is-1692256124135)(E:/学习资料/shell/第四天/笔记/assets/image-20200713101959074.png)]

面试题:单词及字母去重排序

问题

1、按单词出现频率降序排序!
2、按字母出现频率降序排序!

file8.txt 文件内容

No. The Bible says Jesus had compassion2 on them for He saw them as sheep without a shepherd. They were like lost sheep, lost in their sin. How the Lord Jesus loved them! He knew they were helpless and needed a shepherd. And the Good Shepherd knew He had come to help them. But not just the people way back then. For the Lord Jesus knows all about you, and loves you too, and wants to help you.

按照单词出现频率降序

awk -F "[,. ]+" '{for(i=1;i<=NF;i++)S[$i]++}END{for(key in S)print S[key],key}' file8.txt |sort -rn|head

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y12wTHFP-1692256124136)(E:/学习资料/shell/第四天/笔记/assets/image-20200713101616727.png)]

按照字符出现频率降序前10个

awk -F "" '{for(i=1;i<=NF;i++)S[$i]++}END{for(key in S)print S[key],key}' file8.txt |sort -rn|head

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YdigYjWR-1692256124136)(E:/学习资料/shell/第四天/笔记/assets/image-20200713101521632.png)]

面试题:扫描网络内存活主机

问题: 扫描192.168.56.1到192.168.56.254之间ip的是否存活, 并输出是否在线?

服务器ip存活分析

ping ip地址 -c 2
# 如果ip地址存活发送2个数据包会至少接收返回1个数据包

效果如图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ixkHMgFR-1692256124136)(E:/学习资料/shell/第四天/笔记/assets/image-20200713021841637.png)]

完整脚本代码

#!/bin/bash
count=0
for i  in 192.168.56.{1..254}
do
    # 使用ping命令发送2个包测试, 并获取返回接收到包的个数
    receive=$(ping $i -c 2|awk 'NR==6{print $4}')
    # 接收返回包大于0 说明主机在线
    if [ ${receive} -gt 0 ]
    then
        echo "${i} 在线"
        ((count+=1))
    else
        echo "${i} 不在线"
    fi

done
echo "在线服务器有:"$count"个"

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lm44YqhX-1692256124136)(E:/学习资料/shell/第四天/笔记/assets/image-20200713021609950.png)]

面试题:MySQL分库备份

#!/bin/sh
user=root      #用户名
pass=root      #密码
backfile=/root/mysql/backup #备份路径
[ ! -d $backfile ] && mkdir -p $backfile #判断是否有备份路径
cmd="mysql -u$user -p$pass"  #登录数据库
dump="mysqldump -u$user -p$pass " #mysqldump备份参数
dblist=`$cmd -e "show databases;" 2>/dev/null |sed 1d|egrep -v "_schema|mysql"` #获取库名列表
echo "需要备份的数据列表:"
echo $dblist
echo "开始备份:"
for db_name in $dblist #for循环备份库列表
do
 printf '正在备份数据库:%s' ${db_name}
 $dump $db_name 2>/dev/null |gzip >${backfile}/${db_name}_$(date +%m%d).sql.gz #库名+时间备份打包至指定路径下
 printf ',备份完成\n'
done
echo "全部备份完成!!!"

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jy8JtIHN-1692256124137)(E:/学习资料/shell/第四天/笔记/assets/image-20200713032753334.png)]

面试题:MySQL数据库分库分表备份

#!/bin/sh
user=root      #用户名
pass=root      #密码
backfile=/root/mysql/backup #备份路径
[ ! -d $backfile ] && mkdir -p $backfile #判断是否有备份路径
cmd="mysql -u$user -p$pass"  #登录数据库
dump="mysqldump -u$user -p$pass " #mysqldump备份参数
dblist=`$cmd -e "show databases;" 2>/dev/null |sed 1d|egrep -v "_schema|mysql"` #获取库名列表
echo "需要备份的数据列表:"
echo $dblist
echo "开始备份:"
for db_name in $dblist #for循环备份库列表
do
 printf '正在备份数据库:%s\n' ${db_name}
 tables=`mysql -u$user -p"$pass" -e "use $db_name;show tables;" 2>/dev/null|sed 1d`
 for j in $tables
  do
    printf '正在备份数据库 %s 表 %s ' ${db_name} ${j}
    $dump -B --databases $db_name --tables $j 2>/dev/null > ${backfile}/${db_name}-${j}-`date +%m%d`.sql
    printf ',备份完成\n'
  done


 printf '数据库 %s 备份完成\n' ${db_name}
done
echo "全部备份完成!!!"

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a5UIZUlm-1692256124137)(E:/学习资料/shell/第四天/笔记/assets/image-20200713032458346.png)]

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值