以下内容主要来自于博客,我只是用作于快速入门,侵权删 (19条消息) Shell笔记_doordiey的博客-CSDN博客

视频学习参考资料24_尚硅谷_Shell_Awk案例_哔哩哔哩_bilibili

概述

Shell是一个命令行解释器,它接受应用程序/用户命令,然后调用操作系统内核

image-20220905204559736

解析器类型

1
2
3
4
5
[root@ecs-868f-0003 /]# cat /etc/shells
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
  • 我们在日常使用最多的就是sh和bash
  • sh
  • bash
  • nologin
  • dash
  • tcsh
  • csh

其中,sh软链接到bash, centos默认解析器是bash

Shell脚本入门

脚本格式

脚本开头指定解析器

1
#!/bin/bash 

一个输出hello,word的脚本 1.sh

1
2
#!/bin/bash
echo hello,word

执行脚本

1
2
3
4
5
bash 1.sh ---方法1
sh 1.sh ----方法2
source 1.sh ----方法3

./1.sh ----方法4,需要给权限,chmod 777 1.sh

多命令行例子

在指定目录/a下创建一个hey.txt, 在hey.txt 中增加hello

1
2
3
4
#!/bin/bash
cd /a
touch hey.txt
echo hello >> hey.txt

变量

系统变量

  • 定义变量:变量=值
  • 撤销变量: unset变量
  • 声明静态变量: readonly 变量,不能unset

变量定义规则

  • 可以由字母、数字和下划线组成,不能以数字开头,环境变量名建议大写
  • 等号两侧不能有空格
  • 在bash中,变量默认类型是字符串类型,无法直接进行数值运算
  • 变量的值如果有空格,需要引号或者单引号
  • 可把变量提升为全局环境变量,使用export 变量名

特殊变量

$n

n为数字,$n表示该脚本名称,$1-$9表示第一到第九个参数,10以上的参数要用大括号括起来

此处参数表示执行脚本时的参数

演示 3.sh
1
2
3
#!bin/bash
echo "$0 $1 $2"
12
  • 执行3.sh,执行 sh 3.sh ni hao ma
  • 3.sh ni hao (第一个参数是脚本名本身)

$#

获取所有输入参数个数

演示 4.sh
1
2
3
4
#!bin/bash
echo "$0 $1 $2"
echo $#
123
  • 执行4.sh,执行 sh 3.sh ni hao ma

    1
    2
    3
    3.sh ni hao ma

    3(获取到的参数个数,不含脚本名)

∗,@

$*: 代表命令行中所有的参数,把所有参数看成一个整体

$@:代表命令行中所有的参数,把每个参数区分对待

$?

最后一次执行的命令的返回状态,如果该变量的值为0,说明上一次正确执行了,如果返回非0的数字说明没有正确执行。

下面是命令的演示:

1
2
3
4
5
#!/bin/bash
echo "$1 $2 $3"
echo $#
echo $*
echo $@
1
2
3
4
5
6
7
[root@ecs-868f-0003 a]# sh 1.sh ni hao ma
ni hao ma
3
ni hao ma
ni hao ma
[root@ecs-868f-0003 a]# echo $?
0

运算符

  • ( ( 运 算 式 ) ) 或 者 ((运算式))或者((运算式))或者[运算式]
  • expr +,-,*,/, %
  • expr运算符间要有空格

演示

1
2
expr 2 + 3
expr `expr 2 + 3` \* 4

条件判断

基本语法

[ condition ] condition前后要有空格,条件非空即为true

常用判断条件

整数比较

1
2
3
4
5
6
7
= 字符串比较
-lt 小于
-le 小于等于
-eq 等于
-gt 大于
-ge 大于等于
-ne 不等于
1
2
3
[ 23 -lt 80 ]
echo $?
1

文件权限判断

1
2
3
4
-r 读 -w 写 -x 执行
[ -w 1.sh ]
echo $?
1

文件类型判断

1
2
3
4
-f 文件存在且是一个常规文件(file) -e 文件存在(exist) -d 文件存在且是一个文件夹
[ -e 2.sh ]
echo $?
1

if判断

语法

1
2
3
4
5
6
7
8
9
10
11
#其中;隔开两个语句
if [ 条件判断式 ]; then
xxxx
fi

or

if [ 条件判断式 ]
then
程序
fi

注意事项:

  • [ 条件判断式 ], 括号与条件判断式之间必须有空格
  • if 后要有空格

实操

输入一个数字,如果输入1,输出banzhang zhen shuai,如果输入2,输出 jjyaoao yyds,如果是其他,则什么也不输出

1
2
3
4
5
6
7
#!/bin/bash

if [ $1 -eq 1 ]; then
echo "banzhang zhen shuai"
elif [ $1 -eq 2 ]; then
echo "jjyaoao yyds"
fi

case语句

语法

1
2
3
4
5
6
7
8
9
10
11
case $变量名 in
"值1")
xxxx
;;
"值2")
xxxxx
;;
.............
*)
别的都不执行执行这个
esac

实操

需求:输入一个数字,如果是1,则输出jjyaoao,如果是2,则输出hahahaha,输入其他则输出remake

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/sh

case $1 in
1)
echo jjyaoao
;;
2)
echo hahahaha
;;
*)
echo remake
;;
esac
1
2
3
4
5
6
[root@ecs-868f-0003 a]# sh if.sh 1
jjyaoao
[root@ecs-868f-0003 a]# sh if.sh 2
hahahaha
[root@ecs-868f-0003 a]# sh if.sh 3
remake

for循环

语法

1
2
3
4
5
6
7
8
9
10
for (( 初始值;循环控制条件;变量变化 ))  
do
xxxxx
done

or
for 变量 in 值1 值2 值3 ...
do
xxxx
done

练习

计算1-100累加

1
2
3
4
5
6
7
8
#!/bin/sh

ans=0
for((i=1;i<=100;i++))
do
ans=$[ $ans + $i ]
done
echo $ans
1
2
[root@ecs-868f-0003 a]# sh for.sh 
5050

打印所有输入参数

1
2
3
4
5
6
#!/bin/sh

for i in $*
do
echo "jjyaoao like $i"
done
1
2
3
[root@ecs-868f-0003 a]# sh for.sh crystal gala
jjyaoao like crystal
jjyaoao like gala

#@#*的区别

如果取消” “的话也没有区别,” “才可以将空格都连接起来。

1
2
3
4
5
6
7
8
9
10
11
#!/bin/sh

for i in "$*"
do
echo "jjyaoao like $i"
done

for i in "$@"
do
echo "jjyaoao like $i"
done
1
2
3
4
[root@ecs-868f-0003 a]# sh for.sh crystal gala
jjyaoao like crystal gala
jjyaoao like crystal
jjyaoao like gala

while 循环

语法

1
2
3
4
while [ condition ]
do
xxx
done
1
2
3
4
5
6
7
8
9
#!bin/bash
s=0
i=1
while [ $i -le 100 ]
do
s=$[$s + $i]
i=$[$i + 1]
done
echo $s

read读取控制台输出

语法

1
2
read(选项)(参数)
1
  • 选项:
    • -p: 指定读取值时的提示符(返回在命令行的提示语句
    • -t:指定读取值时等待的事件(秒)
  • 参数
    • 变量:指定读取值的变量名

举例

提示12秒内,读取控制台输入的名称

1
2
3
#!bin/bash
read -t 12 -p "你的名字是" Word
echo $Word
1
2
3
[root@ecs-868f-0003 a]# sh read.sh 
你的名字是jjyaoao
jjyaoao

函数

系统函数

basename语法

1
basename [string/ pathname][suffix] 
  • 命令会删除所有的后缀包括最后一个/字符的然后输出字符串
  • 选项:suffix 为后缀,可以把后缀给去了
  • 用来获取文件名

dirname语法

  • dirname 文件绝对路径, 从给定的包含绝对路径的文件名中去除文件名,然后返回剩下的路径
1
2
3
4
5
6
[root@ecs-868f-0003 a]# basename /a/read.sh 
read.sh
[root@ecs-868f-0003 a]# basename /a/read.sh .sh
read
[root@ecs-868f-0003 a]# dirname /a/read.sh
/a

自定义函数

语法

1
2
3
4
5
6
[ function ] funname[()]{    
Action;
[return int;]
}

funname
  • 调用函数地方之间要先声明函数
  • 函数返回值,只能通过$?系统变量获得,可以显示加:return 返回,如果不加,将最后一条命令运行结果做为返回值

练习

计算两个输入参数的和

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/sh

function sum(){
s=0;
s=$[ $1 + $2 ]
echo $s
}

read -p "input your paratemer1:" p1
read -p "input your paratemer2:" p2

sum $p1 $p2
1
2
3
4
[root@ecs-868f-0003 a]# sh sum.sh 
input your paratemer1:23
input your paratemer2:45
68

Shell工具

cut

在文件中剪切数据用,从文件中的每一行剪切字节、字符和字段并将这些字节、字符和字段输出

基本用法

1
cut[选项参数] filename
  • 默认分隔符是制表符
  • 选项参数
    • -f 列号: 提取第几列
    • -d 分隔符,按照指定分隔符分割

举例

1
# test.txt文件内容如下1 y2 i3 j4 o8 l
  • 取第2列 cut -d " " -f 2 test.txt

  • ~~~bash
    [root@ecs-868f-0003 a]# cut -d “ “ -f 2 test.txt
    y2

    1
    2
    3
    4
    5
    6
    7
    8
    9

    ##### 定位截取

    ~~~bash
    [root@ecs-868f-0003 a]# ifconfig eth0
    eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
    inet 192.168.0.194 netmask 255.255.255.0 broadcast 192.168.0.255
    inet6 fe80::f816:3eff:fe70:c78a prefixlen 64 scopeid 0x20<link>
    ............................
1
2
[root@ecs-868f-0003 a]# ifconfig eth0 | grep "inet "
inet 192.168.0.194 netmask 255.255.255.0 broadcast 192.168.0.255
1
2
[root@ecs-868f-0003 a]# ifconfig eth0 | grep "inet " |cut -d " " -f 10
192.168.0.194

最终得到IP地址

sed

一种流编辑器,一次处理一行内容。处理时,把当前处理的行存储在临时缓冲区中,称为模式空间,sed命令处理缓冲区中的内容,处理完成后,把内容送往屏幕,接着处理下一行,不断重复。文件内容不改变,除非你使用重定向存储输出。

基本用法

1
2
sed [选项参数] `command` filename
1
  • 参数说明:
    • -e 直接在指令列模式尚进行sed的动作编辑
  • 命令功能
    • a 新增
    • d 删除
    • s查找并替换

下面将用这串文字进行演示

1
2
3
4
5
6
7
8
# sed.txt
dong shen
guan zhen
mei nv
wo wo
lai lai

le le

打印时在第二行增加字段 00 hj

1
sed '2a 00 hj' sed.txt

删除包含wo的行

1
sed '/wo/d' sed.txt

替换wo为ni

1
sed 's/wo/ni/g' sed.txt

打印时在第二行增加字段 00 hj 替换wo为ni

注意:如果有多行命令需要在命令行执行,那就-e xxx -e xxx

1
sed -e '2a 00 hj' -e 's/wo/ni/g' sed.txt

awk

强大的文本分析工具,把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行分析处理。

基本用法

1
awk [选项参数] 'pattern1{action1}' filename
  • pattern:表示awk再数据中查找的内容
  • action:找到匹配内容时执行命令
  • 选项参数
    • -F:指定输入文件分隔符
    • -v 赋值一个用户定义变量

举例

内置变量

  • filename 文件名
  • nr 已读的记录数
  • nf 浏览记录的域的个数

练习

数据准备

1
[root@ecs-868f-0003 a]# sudo cp /etc/passwd ./
1
2
3
4
5
6
[root@ecs-868f-0003 a]# cat passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
.....................
chrony:x:998:996::/var/lib/chrony:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin

/^root 为正则表达式定位开头

1
[root@ecs-868f-0003 a]# awk -F : '/^root/ {print $7}' passwd

要求:只显示passwd文件的第一列和第七列,以逗号分隔,且在所有航前面添加列名user, shell在最后一行添加”jjyaoao /bin/yyds”

BEGIN为正则条件

1
2
[root@ecs-868f-0003 a]# awk -F : 'BEGIN{print "user, shell"} {print $1 "," $7}
END{print "jjyaoao /bin/yyds"}' passwd
1
2
3
4
5
6
7
user, shell
root,/bin/bash
bin,/sbin/nologin
................
chrony,/sbin/nologin
tcpdump,/sbin/nologin
jjyaoao /bin/yyds

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

ps:环境变量就是:切分的第三个

1
2
3
4
5
6
[root@ecs-868f-0003 a]# awk -F : -v i=1 '{print $3+i}' passwd
1
2
.................
999
73

注意:这里面$3 + i ,而不是 $3 + $i,=-=其实我也不知道为什么

sort

文件排序

基本用法

1
sort(选项)(参数)
  • 选项
    • -n 按照数值大小排序
    • -r 以相反的顺序排序
    • -t 设置排序使用的分隔字符
    • -k 指定需要排序的列
  • 参数
    • 指定待排序文件列表

练习

1
2
3
4
5
6
# sort.sh
bb:40:5.4
bd:20:4.2
xz:50:2.3
cls:10:3.5
jjyaoao:99:1.6
1
2
3
4
5
6
[root@ecs-868f-0003 a]# sort -t : -nrk 2 sort.sh
jjyaoao:99:1.6
xz:50:2.3
bb:40:5.4
bd:20:4.2
cls:10:3.5

企业面试题

image-20220906143346342

注意点: /^$就是空行

image-20220906143733890

-f 为检测文件是否存在

image-20220906143907765image-20220906143853308

就考你知不知道sort命令

金和网络:

请用shell脚本写出查找当前文件夹(/a)下所有文本文件内容中包含有字符”shen”的文件名称

1
2
3
4
5
6
[root@ecs-868f-0003 a]# grep -r shen
sed.txt:dong shen
[root@ecs-868f-0003 a]# grep -r shen /a
/a/sed.txt:dong shen
[root@ecs-868f-0003 a]# grep -r shen /a | cut -d ":" -f 1
/a/sed.txt

The end.