一、概述
Shell是一个命令行解释器,它接收应用程序/用户命令,然后调用操作系统内核。
Shell还是一个功能相当强大的编程语言,易编写、易调试、灵活性强。
Linux提供的Shell解释器
[root@VM-12-10-centos shells]# cat /etc/shells
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
/bin/tcsh
/bin/csh
bash与sh的关系
[root@VM-12-10-centos bin]# ll | grep bash
-rwxr-xr-x 1 root root 922792 12月 19 2021 bash
lrwxrwxrwx 1 root root 10 8月 7 2020 bashbug -> bashbug-64
-rwxr-xr-x 1 root root 6964 4月 1 2020 bashbug-64
-rwxr-xr-x 1 root root 964536 12月 19 2021 bash_onion_sap1013.old
lrwxrwxrwx 1 root root 4 8月 7 2020 sh -> bash
Centos默认的解释器是bash
[root@VM-12-10-centos bin]# echo $SHELL
/bin/bash
二、Shell脚本入门
脚本格式:脚本以
#!/bin/bash
开头(指定解析器)。
# 创建一个Shell脚本,输出hello world
[root@VM-12-10-centos bin]# touch test.sh
[root@VM-12-10-centos bin]# vim test.sh
# 在test.sh中输入以下内容:
#!/bin/bash
echo "hello world"
脚本的常用执行方式:
-
采用
bash 脚本的相对路径或绝对路径
或sh 脚本的相对路径或绝对路径
(不需要赋予脚本执行+x
权限)。-
bash 脚本的相对路径
[root@VM-12-10-centos bin]# bash ./test.sh hello world
-
sh 脚本的绝对路径
[root@VM-12-10-centos bin]# sh /bin/test.sh hello world
-
-
采用输入脚本的绝对路径或相对路径执行脚本(必须具有可执行
+x
权限)。(1)首先赋予
test.sh
脚本的执行+x
权限;[root@VM-12-10-centos bin]# chmod +x test.sh [root@VM-12-10-centos bin]#
(2)执行脚本。
# 相对路径 [root@VM-12-10-centos bin]# ./test.sh hello world # 绝对路径 [root@VM-12-10-centos bin]# /bin/test.sh hello world
注:第一种执行方法,本质是bash解释器帮助执行脚本,所以脚本本身不需要执行权限。而第二种执行方法,本质是脚本需要自己执行,所以需要执行权限。
第三种Shell脚本执行方法:在脚本的路径前加上
.
或source
。假设有以下脚本:
[root@VM-12-10-centos shells]# cat test.sh #!/bin/bash A=1 echo $A
分别使用
sh
,bash
,./
和.
的方式来执行,结果如下:[root@VM-12-10-centos shells]# bash test.sh 1 [root@VM-12-10-centos shells]# echo $A [root@VM-12-10-centos shells]# ./test.sh 1 [root@VM-12-10-centos shells]# echo $A [root@VM-12-10-centos shells]# . test.sh 1 [root@VM-12-10-centos shells]# echo $A 1
前两种方式都是在当前shell中打开一个子shell来执行脚本内容,当脚本内容结束,则子shell关闭,回到父shell中。
第三种,也就是使用在脚本路径前加
.
或者source
的方式,可以使脚本内容在当前shell里执行,而无需打开子shell!这也是为什么我们每次要修改完/etc/profile 文件以后,需要source一下的原因。开子shell与不开子shell的区别就在于,环境变量的继承关系,如在子shell中设置的当前变量,父shell是不可见的。
三、变量
3.1 系统预定义变量
常用系统变量
$HOME
、$PWD
、$SHELL
、$USER
等。
# 查看系统变量的值
[root@VM-12-10-centos shells]# echo $HOME
/root
# 显示当前Shell中所有变量
[root@VM-12-10-centos shells]# set
ABRT_DEBUG_LOG=/dev/null
BASH=/usr/bin/bash
......
3.2 自定义变量
基本语法
- 定义变量:
变量名=变量值
(注:=
前后不能有空格) - 撤销变量:
unset 变量名
- 声明静态变量:
readonly 变量
(注:不能unset
)
变量定义规则
- 变量名称可以由字母、数字和下划线组成,但是不能以数字开头,环境变量名建议大写。
- 等号
=
两侧不能有空格。 - 在bash中,变量默认类型都是字符串类型,无法直接进行数值运算。
- 变量的值如果有空格,需要使用双引号
""
或单引号''
括起来。
-
定义变量A。
[root@VM-12-10-centos shells]# A=1 [root@VM-12-10-centos shells]# echo $A 1
-
给变量A重新赋值。
[root@VM-12-10-centos shells]# A=2
[root@VM-12-10-centos shells]# echo $A
2
3. 撤销变量A。
```bash
[root@VM-12-10-centos shells]# unset A
[root@VM-12-10-centos shells]# echo $A
4. 声明静态变量B=2,不能unset。
```bash
[root@VM-12-10-centos shells]# readonly B=2
[root@VM-12-10-centos shells]# echo $B
2
[root@VM-12-10-centos shells]# B=3
bash: B: readonly variable
5. 在bash中,变量默认类型都是字符串类型,无法直接进行数值运算。
```bash
[root@VM-12-10-centos shells]# C=1+2
[root@VM-12-10-centos shells]# echo $C
1+2
6. 变量的值如果有空格,需要使用双引号或单引号括起来。
```bash
[root@VM-12-10-centos shells]# D= Hello Shell
bash: Hello: command not found
[root@VM-12-10-centos shells]# D="Hello Shell"
[root@VM-12-10-centos shells]# echo $D
Hello Shell
7. 可把变量提升为全局环境变量,可供其他Shell程序使用。
```bash
export 变量名
在test.sh文件中echo $B
[root@VM-12-10-centos shells]# vim test.sh
[root@VM-12-10-centos shells]# cat test.sh
#!/bin/bash
echo "Hello Shell"
echo $B
[root@VM-12-10-centos shells]# ./test.sh
Hello Shell
发现并没有打印输出变量B的值,将变量B提升为全局环境变量后。
[root@VM-12-10-centos shells]# cat test.sh
#!/bin/bash
echo "Hello Shell"
echo $B
[root@VM-12-10-centos shells]# ./test.sh
Hello Shell
[root@VM-12-10-centos shells]# export B
[root@VM-12-10-centos shells]# ./test.sh
Hello Shell
2
## 3.3 特殊变量
### $n
`$n`:n为数字,`$0`代表该脚本名称,`$1`-`$9`代表第一到第九个参数,十以上的参数需要大括号`{}`包含,如`${10}`。
```bash
[root@VM-12-10-centos shells]# vim parameter.sh
[root@VM-12-10-centos shells]# cat parameter.sh
#!/bin/bash
echo '=====$n====='
echo $0
echo $1
echo $2
[root@VM-12-10-centos shells]# chmod 777 parameter.sh
[root@VM-12-10-centos shells]# ./parameter.sh x y
=====$n=====
./parameter.sh
x
y
$#
$#
:获取所有输入参数个数,常用于循环,判断参数的个数是否正确以及加强脚本的健壮性。
[root@VM-12-10-centos shells]# vim parameter.sh
[root@VM-12-10-centos shells]# cat parameter.sh
#!/bin/bash
echo '=====$n====='
echo $0
echo $1
echo $2
echo '=====$#====='
echo $#
[root@VM-12-10-centos shells]# ./parameter.sh x y
=====$n=====
./parameter.sh
x
y
=====$#=====
2
$*、$@
$*
:这个变量代表命令行中所有的参数(把所有的参数看成一个整体)$@
:这个变量也代表命令行中所有的参数(把每个参数区分对待)
[root@VM-12-10-centos shells]# vim parameter.sh
[root@VM-12-10-centos shells]# cat parameter.sh
#!/bin/bash
echo '=====$n====='
echo $0
echo $1
echo $2
echo '=====$#====='
echo $#
echo '=====$*====='
echo $*
echo '=====$@====='
echo $@
[root@VM-12-10-centos shells]# ./parameter.sh x y z ab c
=====$n=====
./parameter.sh
x
y
=====$#=====
5
=====$*=====
x y z ab c
=====$@=====
x y z ab c
$?
$?
:最后一次执行的命令的返回状态。
- 如果这个变量的值为0,证明上一个命令正确执行;
- 如果这个变量的值为非0(具体为何值,由命令自身决定),则证明上一个命令执行不正确。
[root@VM-12-10-centos shells]# ./parameter.sh
=====$n=====
./parameter.sh
=====$#=====
0
=====$*=====
=====$@=====
[root@VM-12-10-centos shells]# echo $?
0
四、运算符
基本语法:
$((运算式))
或$[运算式]
例:计算(2+3)*4的值
[root@VM-12-10-centos shells]# S=$[(2+3)*4]
[root@VM-12-10-centos shells]# echo $S
20
五、条件判断
5.1 基本语法
test 条件
[ 条件 ]
,注:条件前后都要有空格
注:条件飞控即为true,[ x ]
返回true,[ ]
返回false。
5.2 常用判断条件
两个整数之间比较
-eq
等于(equal)-ne
不等于(not equal)-lt
小于(less than)-le
小于等于(less equal)-gt
大于(greater than)-ge
大于等于(greater equal)
注:如果是字符串之间的比较,用=判断相等;用!=判断不相等。
[root@VM-12-10-centos shells]# [ 1 -ge 2 ]
[root@VM-12-10-centos shells]# echo $?
1
[root@VM-12-10-centos shells]# [ 1 -lt 2 ]
[root@VM-12-10-centos shells]# echo $?
0
按照文件权限进行判断
-r
有读的权限(read)-w
有写的权限(write)-x
有执行的权限(execute)
[root@VM-12-10-centos shells]# [ -w parameter.sh ]
[root@VM-12-10-centos shells]# echo $?
0
按照文件类型进行判断
-e
文件存在(existence)-f
文件存在并且是一个常规的文件(file)-d
文件存在并且是一个目录(directory)
[root@VM-12-10-centos shells]# [ -e /home/shells ]
[root@VM-12-10-centos shells]# echo $?
0
[root@VM-12-10-centos shells]# [ -e ./parameter.sh ]
[root@VM-12-10-centos shells]# echo $?
0
[root@VM-12-10-centos shells]# [ -d /home/shells ]
[root@VM-12-10-centos shells]# echo $?
127
多条件判断
&&
表示前一条命令执行成功时,才执行后一条命令;||
表示上一条命令执行失败时,才执行下一条命令。
[root@VM-12-10-centos shells]# [ 1 -eq 2 ] && echo TRUE || echo FALSE
FALSE
[root@VM-12-10-centos shells]# [ 1 -lt 2 ] && echo TRUE || echo FALSE
TRUE
六、流程控制
6.1 if
基本语法:
单分支
if [ 条件判断式 ];then 程序 fi
或
if [ 条件判断式 ] then 程序 fi
多分支
if [ 条件判断式 ] then 程序 elif [ 条件判断式 ] then 程序 else 程序 fi
注意:
[ 条件判断式 ]
中括号和条件判断式之间必须有空格if
后要有空格
例:输入一个数字,如果是0,则输出yes;反之,则输出no。
[root@VM-12-10-centos shells]# vim if.sh
[root@VM-12-10-centos shells]# cat if.sh
#!/bin/bash
if [ $1 -eq 0 ]
then
echo "yes"
else
echo "no"
fi
[root@VM-12-10-centos shells]# chmod u+x if.sh
[root@VM-12-10-centos shells]# ./if.sh
./if.sh: line 3: [: -eq: unary operator expected
no
[root@VM-12-10-centos shells]# ./if.sh 0
yes
[root@VM-12-10-centos shells]# ./if.sh 1
no
6.2 case
基本语法:
case $变量名 in
"值1")
如果变量的值等于值1,则执行程序1
;;
"值2")
如果变量的值等于值2,则执行程序2
;;
...省略其它分支...
*)
如果变量的值都不是以上的值,则执行此程序
;;
esac
注意:
case
行尾必须为单词in
,每一个模式匹配必须以右括号)
结束。- 双分号
;;
表示命令序列结束,相当于java中的break。 - 最后的
*
表示默认模式,相当于java中的default。
例:输入一个数字,如果是1,则输出one;如果是2,则输出two;如果是其它,则输出other。
[root@VM-12-10-centos shells]# vim case.sh
[root@VM-12-10-centos shells]# cat case.sh
#!/bin/bash
case $1 in
"1")
echo "one"
;;
"2")
echo "two"
;;
*)
echo "other"
;;
esac
[root@VM-12-10-centos shells]# chmod 777 case.sh
[root@VM-12-10-centos shells]# ./case.sh 1
one
[root@VM-12-10-centos shells]# ./case.sh 2
two
[root@VM-12-10-centos shells]# ./case.sh 3
other
6.3 for
基本语法1:
for (( 初始值;循环控制条件;变量变化 )) do 程序 done
基本语法2:
for 变量 in 值1 值2 值3... do 程序 done
例:求1-100的和。
[root@VM-12-10-centos shells]# vim for_1.sh
[root@VM-12-10-centos shells]# cat for_1.sh
#!/bin/bash
sum=0
for((i=0;i<=100;i++))
do
sum=$[$sum+$i]
done
echo "sum[1-100] = "$sum
[root@VM-12-10-centos shells]# chmod 777 for_1.sh
[root@VM-12-10-centos shells]# ./for_1.sh
sum[1-100] = 5050
例:打印所有输入参数。
[root@VM-12-10-centos shells]# vim for_2.sh
[root@VM-12-10-centos shells]# cat for_2.sh
#!/bin/bash
for i in a b c
do
echo "输出:$i"
done
[root@VM-12-10-centos shells]# chmod 777 for_2.sh
[root@VM-12-10-centos shells]# ./for_2.sh
输出:a
输出:b
输出:c
$*
与$@
的区别:
$*
与$@
都表示传递给函数或脚本的所有参数,不被双引号""
包含时,都以$1 $2 ...$n
的形式输出所有参数。[root@VM-12-10-centos shells]# vim for_3.sh [root@VM-12-10-centos shells]# cat for_3.sh #!/bin/bash echo '=====$*=====' for i in $* do echo "输出:$i" done echo '=====$@=====' for j in $@ do echo "输出:$j" done [root@VM-12-10-centos shells]# chmod 777 for_3.sh [root@VM-12-10-centos shells]# ./for_3.sh a b c =====$*===== 输出:a 输出:b 输出:c =====$@===== 输出:a 输出:b 输出:c
当两者被双引号
""
包含时,$*
会将所有的参数作为一个整体,以$1 $2 ...$n
的形式输出所有参数;$@
会将各个参数分开,以$1
$2
…$n
的形式输出所有参数。[root@VM-12-10-centos shells]# vim for_4.sh [root@VM-12-10-centos shells]# cat for_4.sh #!/bin/bash echo '=====$*=====' for i in "$*" # $*中的所有参数看成是一个整体,所以这个 for 循环只会循环一次 do echo "输出:$i" done echo '=====$@=====' for j in "$@" # $@中的每个参数都看成是独立的,所以"$@"中有几个参数,就会循环几次 do echo "输出:$j" done [root@VM-12-10-centos shells]# chmod 777 for_4.sh [root@VM-12-10-centos shells]# ./for_4.sh a b c =====$*===== 输出:a b c =====$@===== 输出:a 输出:b 输出:c
6.4 while
基本语法:
while [ 条件判断式 ]
do
程序
done
例:求1-100的和。
[root@VM-12-10-centos shells]# vim while.sh
[root@VM-12-10-centos shells]# cat while.sh
#!/bin/bash
sum=0
i=1
while [ $i -le 100 ]
do
sum=$[$sum+$i]
i=$[$i+1]
done
echo "sum[1-100] = $sum"
[root@VM-12-10-centos shells]# chmod 777 while.sh
[root@VM-12-10-centos shells]# ./while.sh
sum[1-100] = 5050
七、read读取控制台输入
7.1 基本语法
read (选项) (参数)
- 选项:
-p
:指定读取值时的提示符;-t
:指定读取值时等待的时间(秒),如果-t
不加表示一直等待。
- 参数:变量,指定读取值的变量名。
[root@VM-12-10-centos shells]# vim read.sh
[root@VM-12-10-centos shells]# cat read.sh
#!/bin/bash
read -t 7 -p "请在7秒内输入x变量的值:" x
echo $x
[root@VM-12-10-centos shells]# chmod 777 read.sh
[root@VM-12-10-centos shells]# ./read.sh
请在7秒内输入x变量的值:123
123
八、函数
8.1 系统函数
basename
基本语法:
basename [string/pathname] [suffix]
:basename命令会删掉所有的前缀包括最后一个/
字符,然后将字符串显示出来
basename
可以理解为取路径里的文件名称。suffix
为后缀,如果suffix被指定了,basename会将pathname或string中的suffix去掉。
例:截取/home/shells/test.sh路径的文件名称。
[root@VM-12-10-centos shells]# basename /home/shells/test.sh
test.sh
[root@VM-12-10-centos shells]# basename /home/shells/test.sh .sh
test
dirname
基本语法:
dirname 文件绝对路径
:从给定的包含绝对路径的文件名中去除文件名(非目录的部分),然后返回剩下的路径(目录的部分)。
dirname
可以理解为取文件路径的绝对路径名称。
例:截取/home/shells/test.sh文件的路径。
[root@VM-12-10-centos shells]# dirname /home/shells/test.sh
/home/shells
自定义函数
基本语法
[function] funname[()]
{
Action;
[return int;]
}
- 必须在调用函数之前,先声明函数,shell脚本是逐行运行。不会像其它语言一样先编译。
- 函数返回值,只能通过
$?
系统变量获得,可以显示加return
返回;如果不佳,将以最后一条命令运行结果,作为返回值。return后跟数值n(0-255)。
例:计算两个输入参数的和。
[root@VM-12-10-centos shells]# vim fun.sh
[root@VM-12-10-centos shells]# cat fun.sh
#!/bin/bash
function sum()
{
a=0
a=$[$1+$2]
echo "$a"
}
read -p "请输入第一个数字:" x;
read -p "请输入第二个数字:" y;
sum $x $y;
[root@VM-12-10-centos shells]# chmod 777 fun.sh
[root@VM-12-10-centos shells]# ./fun.sh
请输入第一个数字:2
请输入第二个数字:3
5
九、正则表达式
正则表达式使用单个字符串来描述、匹配一系列符合某个语法规则的字符串。在很多文本编辑器中,正则表达式通常被用来检索、替换符合某个格式的文本。
在Linux中,grep、sed、awk等文本处理工具都支持通过正则表达式进行模式匹配。
9.1 常规匹配
一串不包含特殊字符的正则表达式匹配指定的字符串。
例:匹配所有包含spool的行。
[root@VM-12-10-centos shells]# cat /etc/passwd | grep spool
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
9.2 常用特殊字符
特殊字符:^
^
匹配一行的开头。
例:匹配所有以root开头的行。
[root@VM-12-10-centos shells]# cat /etc/passwd | grep ^root
root:x:0:0:root:/root:/bin/bash
特殊字符:$
$
匹配一行的结束。
例:匹配所有以lt结尾的行。
[root@VM-12-10-centos shells]# cat /etc/passwd | grep lt$
halt:x:7:0:halt:/sbin:/sbin/halt
特殊字符:.
.
匹配一个任意的字符。
例:匹配含r和t且两者之间有且值存在两个字符的行。
[root@VM-12-10-centos shells]# cat /etc/passwd | grep r..t
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
特殊字符:*
*
表示匹配上一个字符0次或多次。不单独使用,与上一个字符连用。
例:匹配含ro和t且ro在前,t在后的所有行。
[root@VM-12-10-centos shells]# cat /etc/passwd | grep ro*t
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
abrt:x:173:173::/etc/abrt:/sbin/nologin
字符区间:[]
[]
表示匹配某个范围内的一个字符。例:
[6,8]
:匹配6或8[0-9]
:匹配一个0-9的数字[0-9]*
:匹配任意长度的数字字符串[a-z]
:匹配一个a-z之间的字符[a-z]*
:匹配任意长度的字符字符串[a-c,e-g]
:匹配a-c或e-g之间的任意字符
[root@VM-12-10-centos shells]# cat /etc/passwd | grep r[a,b,c]*t
operator:x:11:0:operator:/root:/sbin/nologin
abrt:x:173:173::/etc/abrt:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
特殊字符:\
\
表示转义,并不会单独使用。由于所有特殊字符都有其特定匹配模式,当需要匹配某一特殊字符本身时(例:需查找所有包含$
的行),就会很困难,此时需要将转义字符和特殊字符连用**(需要使用单引号将表达式引起来)**,来表示特殊字符本身。
例:查找所有包含:/bin
的行。
[root@VM-12-10-centos shells]# cat /etc/passwd | grep ':\/bin'
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
syslog:x:996:994::/home/syslog:/bin/false
lighthouse:x:1000:1000::/home/lighthouse:/bin/bash
postgres:x:26:26:PostgreSQL Server:/var/lib/pgsql:/bin/bash
mysql:x:1001:1001::/home/mysql:/bin/bash
十、文本处理工具
10.1 cut
cut
就是剪,在文件中负责剪切数据使用的。cut命令从文件的每一行剪切字节、字符和字段并将这些字节、字符和字段输出。
基本语法:
cut [选项参数] filename
默认分隔符是制表符。
选项参数说明:
-f
:列号,提取第几列。-d
:分隔符,按照指定分隔符分隔列,默认就是制表符\t
。-c
:按字符进行切割后加n
,表示取第几列。例:按字符切割后取第一列-c 1
。
例:切割cut.txt文件第一列,切割cut.txt文件第二、三列。
[root@VM-12-10-centos shells]# vim cut.txt
[root@VM-12-10-centos shells]# cat cut.txt
文本 分 制
处理 隔 表
工具 符 符
[root@VM-12-10-centos shells]# cut -d " " -f 1 cut.txt
文本
处理
工具
[root@VM-12-10-centos shells]# cut -d " " -f 2,3 cut.txt
分 制
隔 表
符 符
例:在cut.txt文件中切割出处理。
[root@VM-12-10-centos shells]# cat cut.txt | grep 处理 | cut -d " " -f 1
处理
例:获取系统PATH变量值第二个:
开始后的所有路径。
[root@VM-12-10-centos shells]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/usr/local/mysql/bin
[root@VM-12-10-centos shells]# echo $PATH | cut -d ":" -f 3-
/usr/sbin:/usr/bin:/root/bin:/usr/local/mysql/bin
10.2 awk
awk
:一个强大的文本分析工具,把文件逐行读入,以空格为默认分隔符将每行切片,切开的部分再进行分析处理。
基本语法:
awk [选项参数] '/pattern/{action} /pattern/{action}...' filename
pattern
:表示awk在数据中查找的内容,就是匹配模式。action
:在找到匹配内容时所执行的一系列命令。选项参数说明:
-F
:指定输入文件分隔符。-v
:赋值一个用户定义变量。awk的内置变量:
FILENAME
:文件名。NR
:已读的记录数(行号)。NF
:浏览记录的域的个数(切割后列的个数)。
# 数据准备
[root@VM-12-10-centos shells]# sudo cp /etc/passwd ./
# passwd数据的含义:
# 用户名:密码(加密过后的):用户 id:组 id:注释:用户家目录:shell 解析器
# 搜索passwd文件以root关键字开头的所有行,并输出该行的第7列
[root@VM-12-10-centos shells]# awk -F : '/^root/{print $7}' passwd
/bin/bash
# 搜索passwd文件以root关键字开头的所有行,并输出该行的第1列和第7列,中间以,号分割
[root@VM-12-10-centos shells]# awk -F : '/^root/{print $1","$7}' passwd
root,/bin/bash
# 只有匹配了pattern的行才会执行action
# 只显示/etc/passwd中以r开头第一列和第七列,以逗号分割,且在所有行前面添加列名user,shell在最后一行添加xxx,/bin/xxxx
[root@VM-12-10-centos shells]# awk -F : 'BEGIN{print "user,shell"} /^r/{print $1","$7} END{print "xxx,/bin/xxxx"}' passwd
user,shell
root,/bin/bash
rpc,/sbin/nologin
xxx,/bin/xxxx
# BEGIN在所有数据读取行之前执行
# END在所有数据执行之后执行
# 将passwd文件中以r开头的用户id增加数值1并输出
[root@VM-12-10-centos shells]# awk -v i=1 -F : '/^r/{print $3+i}' passwd
1
33
# 统计passwd文件名,每行的行号,每行的列数
[root@VM-12-10-centos shells]# awk -F : '{print "filename:" FILENAME ",linenum:" NR ",col:" NF}' passwd
filename:passwd,linenum:1,col:7
filename:passwd,linenum:2,col:7
filename:passwd,linenum:3,col:7
filename:passwd,linenum:4,col:7
# ......
# 查询ifconfig命令输出结果中的空行所在的行号
[root@VM-12-10-centos shells]# ifconfig | awk '/^$/{print NR}'
9
18
# 切割ip
[root@VM-12-10-centos shells]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.0.12.10 netmask 255.255.252.0 broadcast 10.0.15.255
inet6 fe80::5054:ff:fe2b:8e1e prefixlen 64 scopeid 0x20<link>
# ......
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@VM-12-10-centos shells]# ifconfig eth0 | awk '/netmask/ {print $2}'
10.0.12.10
十一、应用案例
归档文件
实现一个每天对指定目录归档备份的脚本,输入一个目录名称(末尾不带/
),将目录下所有文件按天归档保存,并将归档日期附加在归档文件名上,放在/home/bak
下。
使用归档命令tar
,后面可以加上-c
选项表示归档,加上-z
选项表示同时进行压缩,得到的文件后缀名为.tar.gz
。
[root@VM-12-10-centos shells]# vim bak.sh
[root@VM-12-10-centos shells]# cat bak.sh
#!/bin/bash
# 判断输入参数个数是否为1
if [ $# -ne 1 ]
then
echo "参数个数错误!应输入一个参数,作为归档目录名。"
exit;
fi
# 从参数中获取目录名称
if [ -d $1 ]
then
echo
else
echo
echo "目录不存在!"
echo
exit
fi
DIR_NAME=$(basename $1)
DIR_PATH=$(cd $(dirname $1); pwd)
# 获取当前日期
DATE=$(date +%Y-%m-%d)
# 定义生成的归档文件名称
FILE=bak_${DIR_NAME}_$DATE.tar.gz
BAK_DIR=/home/bak
# 判断备份路径是否存在
if [ ! -d "$BAK_DIR" ];then
echo
echo "备份目录不存在"
mkdir $BAK_DIR
echo
else
echo
echo "备份目录已存在!"
echo
fi
DEST=${BAK_DIR}/$FILE
# 开始归档目录文件
echo "开始归档..."
echo
# 加-P打包屏蔽提示 tar: 从成员名中删除开头的“/”
tar -czf $DEST $DIR_PATH/$DIR_NAME
if [ $? -eq 0 ]
then
echo
echo "归档成功!"
echo "归档文件:$DEST"
echo
else
echo "归档失败!"
echo
fi
exit
[root@VM-12-10-centos shells]# ./bak.sh /home/shells/
备份目录已存在!
开始归档...
tar: 从成员名中删除开头的“/”
归档成功!
归档文件:/home/bak/bak_shells_2023-03-08.tar.gz
[root@VM-12-10-centos shells]#
发送消息
利用Linux自带的mesg和write工具,向其它用户发送消息。
实现一个向某个用户快速发送消息的脚本,输入用户名作为第一个参数,后面直接跟要发送的消息。脚本需要检测用户是否登录在系统中、是否打开消息功能,以及当前发送消息是否为空。
[root@VM-12-10-centos shells]# vim message.sh
[root@VM-12-10-centos shells]# cat message.sh
#!/bin/bash
login_user=$(who | grep -i -m 1 $1 | awk '{print $1}')
if [ -z $login_user ]
then
echo "$1 不在线!"
echo "脚本退出.."
exit
fi
is_allowed=$(who -T | grep -i -m 1 $1 | awk '{print $2}')
if [ $is_allowed != "+" ]
then
echo "$1 没有开启消息功能"
echo "脚本退出.."
exit
fi
if [ -z $2 ]
then
echo "没有消息发出"
echo "脚本退出.."
exit
fi
whole_msg=$(echo $* | cut -d " " -f 2- )
user_terminal=$(who | grep -i -m 1 $1 | awk '{print $2}')
echo $whole_msg | write $login_user $user_terminal
if [ $? != 0 ]
then
echo "发送失败!"
else
echo "发送成功!"
fi
[root@VM-12-10-centos shells]# ./message.sh mysql
mysql 不在线!
脚本退出..
[root@VM-12-10-centos shells]# ./message.sh root hello
Message from root@VM-12-10-centos on pts/0 at 21:24 ...
hello
EOF
发送成功!
标签:10,12,centos,shells,VM,笔记,学习,Shell,root
From: https://blog.csdn.net/weixin_45563821/article/details/140252678