Linux文本处理和shell基础

188 阅读10分钟

1. 权限总结,属性及ACL相关命令及选项,示例。

用户和组的配置文件

/etc/passwd #用户及其属性信息

/etc/shadow #用户密码及其相关属性

/etc/group #组及其属性信息

/etc/gshadow #组密码及其相关属性

文件权限的三种角色

角色英文字符
属主:所有者useru
属组groupg
其他用户:组外的用户othero

三种权限

权限英文字符八进制
读权限readr4
写权限writew2
执行权限executex1

[czx@ubuntu2204 ~]$ ls -l /etc/passwd

-rw-r--r-- 1 root root 1944 Jul 17 09:03 /etc/passwd

权限 所有者 所属组 大小 修改和创建时间 文件名

文件所有者和属组属性操作

设置文件的所有者chown

chown命令可以修改文件的属主,也可以修改属组

#用法说明

OWNER #只修改所有者

OWNER:GROUP #同时修改所有者和属组

:GROUP #只修改属组,冒号也可以用.替换

-R #递归写法

[root@ubuntu2204 test]# chown jose a1.txt 
[root@ubuntu2204 test]# chown jose. a2.txt 
[root@ubuntu2204 test]# chown jose: a3.txt 
[root@ubuntu2204 test]# ls -lh
total 0
-rw-r--r-- 1 jose root 0 Jul 17 14:55 a1.txt
-rw-r--r-- 1 jose jose 0 Jul 17 14:55 a2.txt
-rw-r--r-- 1 jose jose 0 Jul 17 14:55 a3.txt
-rw-r--r-- 1 root root 0 Jul 17 14:55 a4.txt
-rw-r--r-- 1 root root 0 Jul 17 14:55 a5.txt
-rw-r--r-- 1 root root 0 Jul 17 14:55 a6.txt
也可以用UID修改属主,但是不能用.和冒号来省略简写
chown 1000 a4.txt
chown 1000.1000 a5.txt

根据文件修改,根据a1的权限修改a2
chown --reference=a1.txt a2.txt
设置文件的属组信息chgrp

文件权限

角色命令中的字符备注
owneru属主
groupg属组
othero其他用户
alla所有人

赋值写法

+		#增加权限
-		#删除权限
=		#覆盖写法

常用写法

u+r		#属主加读权限
g-x		#属组去除执行权限
ug=rx	#属主属组权限改为rx读和执行
o=		#other用户无任何权限
a=rwx	#所有用户有读写执行,相当于777
u+r,g-x	#属主加读权限,属组去除执行权限,同时指定

注意

用户的最终权限是从左到右匹配,一旦匹配权限立即生效,不再向右查看权限。比如属主是tom的文件,tom查看该文件匹配为属主,直接按属主权限生效。

r和w权限对root用户无效,对没有读写权限的文件,root用户也可以读写。

只要所有者,所属组或other之一有x权限,root就可以执行。

修改文件权限chmod
chmod 
who opt permisson
who			# u|g|o|a

opt			# +|-|=

permisson	# r|w|x

chmod u=r,g=w,o=x f2
chmod u+w,g-x,o-r f3
chmod a=rwx	f4
chmod a= f6	#去除所有权限
chmod 777 f5

-R		#递归

#大写X,只会给子目录+x权限
chmod o+X -R /dir1

新建文件和目录的默认权限

linux新建文件或目录,都有默认权限

root创建文件644,创建目录755

普通用户创建文件664,创建目录775

umask值间接影响新建文件和新建目录的权限:

新建文件:666-umask,按位对应相减,如果所得结果某位存在执行(奇数)权限,则该位+1;确保新创建的文件不能有执行权限

新建目录:777-umask

Linux文件系统上的特殊权限

除了rwx外,还有3个特殊权限,SUID,SGID,Sticky;这三个特殊权限独立于rwx权限;

特殊权限

SUID:作用于二进制可执行文件上,用户将继承此程序所有者的权限;

SGID:作用于二进制可执行文件上,用户将继承此程序所有组的权限;

作用于目录上,此目录新建的文件的所属组将自动从此目录继承;

STICKY:作用于目录上,此目录中的文件只能由所有者自己来删除;

权限字符表示八进制表示备注
SUIDs4如果原属主没有可执行权限,再加SUID权限,则显示为S
SGIDs2如果原属组没有可执行权限,再加SGID权限,则显示为S
STICKYt1如果other没有可执行权限,再加STICKY权限,则显示为T
特殊权限SUID

前提:进程有属主和属组;文件有属主和属组

二进制可执行文件上SUID权限功能:

任何一个可执行程序文件能不能启动为进程:取决于发起者对程序文件是否有执行权限

启动为进程后,其进程的属主为原程序文件的属主

SUID只对二进制可执行程序有效

SUID设置在目录上无意义

chmod u+s FILE
chmod 4xxx FILE
chmod u-s FILE
特殊权限SGID

二进制可执行文件上SGID权限功能:

启动为进程后,其进程的属组为原程序文件的属组

特殊权限SGID

二进制可执行文件上SGID权限功能:

启动为进程后,其进程的属组为原程序文件的属组

目录上的SGID权限功能:

默认情况下,用户创建文件时,其属组为此用户所属的主组,一旦某目录被设定SGID,则对此目录有写权限的用户在此目录中创建的文件所属的组为此目录的属组,通常用于创建一个协作目录。

特殊权限STICKY

具有写权限的目录通常用户可以删除目录中的任何文件,无论该文件的权限或拥有权

在目录设置sticky位,只有用户的所有者或者root可以删除该文件

sticky设置在文件无意义

chmod o+t DIR
chmod 1xxx DIR
chmod o-t DIR
设定文件特殊属性
chattr

 -p project	        #设置文件项目编号
-R			#递归执行
-V			#显示过程
-f			#不输出错误信息

#操作符
+attribute		#添加该属性
-attribute		#去掉该属性
=attribute		#仅有该属性

#常用属性
a				#对文件:可追加内容,不可被删除,不可被修改,不可被重命名;对目录,可新建,修改文件,但不可删除文件
一般用于日志,只能追加内容。
A				#不更新atime,节省IO
c				#文件被压缩保存
i				#对文件:不可被删除不可被修改不可重命名;对目录:可修改查看目录中的文件,不可新建文件,不可删除文件
s				#彻底删除文件,用0填充原来的数据块
u				#防止误删除,这里指原来存储该文件的块不会被新的数据覆盖、

lsattr			#显示文件特殊权限
[root@ubuntu2204 ~]# lsattr test.txt 
--------------e------- test.txt		#e为文件系统自带

访问控制列表ACL

ACL权限功能

rwx权限体系中,仅仅只能将用户分为3种角色,要对单独的用户设置额外的权限,则无法实现;

Centos7默认创建的xfs和ext4文件系统就有ACL功能

Centos7之前,默认手工创建的ext4文件系统无ACL,需手动添加

tune2fs -o acl /dev/sdb1
mount -o acl /dev/sdb1 /mnt/test

ACL生效顺序: 所有者,自定义用户,所属组,自定义组,其他人

ACL相关命令:

setfacl可设置ACL权限

getfacl可查看设置的ACL权限

apt install acl

setfacl
-m		#修改acl权限
-x		#删除acl权限
-b		#删除所有acl权限

[root@ubuntu2204 tmp]# ls -lh f1
-rw-r--r-- 1 root root 4 Jul 18 14:46 f1
[root@ubuntu2204 tmp]# getfacl f1
# file: f1
# owner: root
# group: root
user::rw-
group::r--
other::r--
初始没acl,设置tom用户对f文件没有任何权限
[root@ubuntu2204 tmp]# setfacl -m u:tom:- f1 
[root@ubuntu2204 tmp]# getfacl f1
# file: f1
# owner: root
# group: root
user::rw-
user:tom:---
group::r--
mask::r--
other::r--
[root@ubuntu2204 tmp]# setfacl -x u:tom f1

#修改组的acl权限
setfacl -m g:tom:rw f2

从文件复制ACL

getfacl f1 | setfacl --set-file=- f2

对于脚本程序来说,必须先要有读权限,才能执行,不能光有执行权限(root除外shell)

2. 结合vim几种模式,学会使用vim几个常见操作。

1)如何打开文件。并在打开文件(命令模式)之后如何退出文件。

vi编辑器、nano编辑器、vim编辑器等来打开文件。 打开后在命令模式冒号+q回车退出文件,wq保存并退出,加感叹号!表示强制退出。

2)打开文件(命令模式)之后,进入插入模式。并在插入模式中如何回到打开文件的状态(命令模式),并在命令模式之后如何退出文件。

插入模式按esc回到命令模式,命令模式冒号+q退出文件。

3)打开文件(命令模式)之后,进入插入模式,编写一段话, 之后从插入模式中如何回到打开文件的状态(命令模式),并在命令模式之后如何退出文件。

image.png

按esc回到名字模式,:wq保存并退出文件。

4)使用cat命令验证文件内容,是刚刚自己写的内容。

image.png

3. 总结文本处理工具,文件查找工具,文本处理三剑客, 文本格式化命令(printf)的相关命令及选项,示例。

1) 文本处理工具

文件内容查看命令

cat可以查看文本内容
-E		#显示行结束符$
-A		#显示所有控制符
-n		#对显示的每一行编号
-b		#非空行编号
-s		#压缩连续的空行成一行
nc也可以查看文本内容,相当于cat -b
[root@ubuntu2204 ~]# nl test.txt 
     1	abc
       
     2	123
     3	abd
       
       
     4	adsadsada
       
     5	dsadsadsadsaas
       
       
     6	sdasdsadasdsa
分页查看文本内容:

more

-d		#在底部显示提示
-s		#压缩连续空行

空格翻页
回车下一行

less也可以实现分页查看文件

显示文本前面或后面的行内容

head 可以显示文件或标准输入的前面行,默认不加参数是前10行

-c		#获取前n字节
-n		#获取前n行

tail和head相反,查看文件或标准输入的倒数行,默认也是10行

-c		#获取后n字节
-n		#获取后n行
-f		#跟踪显示文件新追加的内容,常用日志监控。如果同名文件被删除后再新建,无法追踪
-F		#与f相同,但同名文件被删除后再新建,也能继续追踪
[root@ubuntu2204 ~]# tail /var/log/kern.log
Aug 11 08:33:09 ubuntu2204 kernel: [    9.027773] RPC: Registered udp transport module.
Aug 11 08:33:09 ubuntu2204 kernel: [    9.027774] RPC: Registered tcp transport module.
Aug 11 08:33:09 ubuntu2204 kernel: [    9.027775] RPC: Registered tcp NFSv4.1 backchannel transport module.
Aug 11 08:33:09 ubuntu2204 kernel: [    9.147816] NET: Registered PF_VSOCK protocol family
Aug 11 08:33:09 ubuntu2204 kernel: [   10.085104] e1000: ens33 NIC Link is Up 1000 Mbps Full Duplex, Flow Control: None
Aug 11 08:33:09 ubuntu2204 kernel: [   10.086113] IPv6: ADDRCONF(NETDEV_CHANGE): ens33: link becomes ready
Aug 11 08:33:09 ubuntu2204 kernel: [   12.586242] Process accounting resumed
Aug 11 08:33:09 ubuntu2204 kernel: [   13.224384] loop6: detected capacity change from 0 to 8
Aug 11 08:58:19 ubuntu2204 kernel: [ 1458.839093] e1000: ens33 NIC Link is Down
Aug 11 08:58:25 ubuntu2204 kernel: [ 1464.890322] e1000: ens33 NIC Link is Up 1000 Mbps Full Duplex, Flow Control: None

[root@ubuntu2204 ~]# head /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin

按列抽取文本cut

-b		#按字节分割,指定要显示的列
-c		#按字符分割,指定要分割的列
-d		#指定分隔符,默认是tab
-f		#要显示的列
--output-delimiter=STRING	#输出的时候用指定字符提换分隔符
-z		#以NULL字符而非换行符作为行尾分隔符

[root@ubuntu2204 ~]# ifconfig cut -d":" -f1-3,7 /etc/passwd | head -5
root:x:0:/bin/bash
daemon:x:1:/usr/sbin/nologin
bin:x:2:/usr/sbin/nologin
sys:x:3:/usr/sbin/nologin
sync:x:4:/bin/sync

[root@ubuntu2204 ~]# ifconfig ifconfig | head -2 | tail -1 | tr -s " " | cut -d' ' -f3
192.168.141.128

[root@ubuntu2204 ~]# df | tr -s " " | cut -d" " -f5 | tr -d '[a-zA-z%]'

1
9
0
0
14
1

[root@ubuntu2204 ~]# echo {1..10} | cut -d' ' -f1-10 --output-delimiter="+"
1+2+3+4+5+6+7+8+9+10
[root@ubuntu2204 ~]# echo {1..10} | cut -d' ' -f1-10 --output-delimiter="+" |bc
55
paste合并多个文件同行号的内容
[root@ubuntu2204 ~]# paste abc.txt 123.txt 
a	1
b	2
c	3
d	4
e	5
f	6
g	7
h	8
i	9
[root@ubuntu2204 ~]# paste -d":" abc.txt 123.txt 
a:1
b:2
c:3
d:4
e:5
f:6
g:7
h:8

分析文本的工具

文本数据统计:wc

整理文件:sort

比较文件:diff和path

收集文本统计数据wc
wc
-l		#只统计行数
-w		#只统计单词总数
-c		#只统计字节总数
-m		#只统计字符总数
-L		#只显示文件中最长行的长度

[root@ubuntu2204 ~]# wc -l /etc/passwd
35 /etc/passwd
文本排序sort
sort
-n		#按数字排序
-r		#倒序

[root@ubuntu2204 ~]# df | tr -s ' ' % | cut -d"%" -f5 | tr -d '[a-zA-Z]'  | sort -rn |head -1
14
去重uniq

uniq命令从输入中删除前后相接的重复的行,常和sort配合使用

uniq

-c		#显示重复行出现的次数
-d		#仅显示有重复的行
-u		#仅显示不重复的行
文件比较

diff

vimdiff vim打开不同文件比较

cmp 查看二进制文件的不同

2) 文件查找工具

在文件系统上查找符合条件的文件

文件查找

非实时查找(数据库查找):locate

实时查找:find

locate非实时搜索

locate查询系统上预建的文件索引数据库/var/lib/mlocate/mlocate.db,Ubuntu上是plocate

索引的构建是在系统较为空闲时自动进行(周期任务),执行updatedb可以更新数据库

索引构建过程需要遍历整个根文件系统,很消耗资源

localte和update命令来自于mlocate包

工作特点:

查找速度快

模糊查找

非实时查找

搜索的是文件全路径,不仅仅是文件名

可能只搜索用户具备读取和执行权限的目录

格式:

locate option pattern

-A		#输出所有能匹配的文件名,不管文件是否存在
-b		#仅匹配文件名部分,并不匹配路径中的内容
-c		#只输出找到的数量
-d		#指定数据库
-e		#仅打印当前现有文件的条目
-r		#启用正则

范例:locatedb更新数据库

#新建的文件需要更新数据库
[root@ubuntu2204 ~]# updatedb
#打印前三个
[root@ubuntu2204 ~]# locate -n 3 conf
/boot/config-5.15.0-113-generic
/boot/config-5.15.0-94-generic
/boot/grub/i386-pc/configfile.mod

范例

#搜索etc目录下a开头文件
locate /etc/a
#仅搜索文件名包含share的文件
locate -b share
#统计数量
locate -c conf
#使用基本正则
locate -r '\.conf$'

find实时搜索

find是实时查找工具,通过遍历指定路径完成文件查找

工作特点:

查找速度略慢

精确查找

实时查找

查找条件丰富

可能只搜索用户具备读取和执行权限的目录

格式: find option 查找路径 查找条件 处理动作

查找路径:指定具体目标路径,默认为当前目录

查找条件:指定的查找标准,可以文件名、大小、类型、权限等标准进行;默认为找出指定路径下的所有文件

处理动作:对符合条件的的文件做操作,默认输出至屏幕

指定搜索目录层级

-maxdepth N		#最大搜索目录深度,指定目录下的文件为第1级
-mindeth N		#最小搜索目录深度

根据文件名和inode查找

-name name		#支持使用glob,如:*,?,[],[^],通配符要加双引号引起来
-iname name		#不区分字母大小写
-inum number	#按inode号查找
-links n		#链接数为n的文件

范例:

#按文件名查找
[root@ubuntu2204 ~]# find / -name passwd
/snap/core20/2318/etc/pam.d/passwd
/snap/core20/2318/etc/passwd
/snap/core20/2318/usr/bin/passwd
/snap/core20/2318/usr/share/bash-completion/completions/passwd
/snap/core20/2318/usr/share/doc/passwd
/snap/core20/2318/usr/share/lintian/overrides/passwd
#通配符
[root@ubuntu2204 ~]#  find -name "*txt"
./10.txt
./test/f-9.txt
./test/f-6.txt
./test/f-8.txt
./test/f-1.txt
./test/f-7.txt
./test/f-10.txt
./test/f-4.txt
./test/f-3.txt
./test/f-5.txt
./test/f-2.txt

根据属主属组查找

-user USERNAME		#查找属主为指定用户(UID)的文件
-group
-uid
-gid
-nouser				#查找没有属主的文件
-nogroup

根据文件类型查找

-type	TYPE	#指定文件类型

#type 值
f		#普通文件
d		#目录文件
l		#符号链接文件
s		#套接字文件
b		#块设备文件
c		#字符设备文件
p		#管道文件

配合处理动作

#多条件查找要将条件()起来,不然ls只ls最后的条件
[root@ubuntu2204 ~]# find -name "*.txt" -ls
  3538963      4 -rw-r--r--   1 root     root            9 Jul 23 07:06 ./10.txt
  3538973      0 -rw-r--r--   1 root     root            0 Jul 23 07:25 ./test/f-9.txt
  3538970      0 -rw-r--r--   1 root     root            0 Jul 23 07:25 ./test/f-6.txt
  3538972      0 -rw-r--r--   1 root     root            0 Jul 23 07:25 ./test/f-8.txt
  3538964      0 -rw-r--r--   1 root     root            0 Jul 23 07:25 ./test/f-1.txt
  3538971      0 -rw-r--r--   1 root     root            0 Jul 23 07:25 ./test/f-7.txt
  3538974      0 -rw-r--r--   1 root     root            0 Jul 23 07:25 ./test/f-10.txt
  3538968      0 -rw-r--r--   1 root     root            0 Jul 23 07:25 ./test/f-4.txt
  3538967      0 -rw-r--r--   1 root     root            0 Jul 23 07:25 ./test/f-3.txt
  3538969      0 -rw-r--r--   1 root     root            0 Jul 23 07:25 ./test/f-5.txt
  3538966      0 -rw-r--r--   1 root     root            0 Jul 23 07:25 ./test/f-2.txt

根据权限查找

-perm [+|-]N

MODE	#精确权限匹配,必须一样的权限
/MODE	#任何一类(u,g,o)对象的权限中有一位匹配即可,表示或关系
-MODE	#每一类对象都必须有指定权限,表示与关系

[root@ubuntu2204 ~]# find -perm 644
./HPE_Linux
./fstab
./.profile
./10.txt
./10.txt.bak
./.bashrc
./.log
./.sudo_as_admin_successful
./passwd
./.cache/motd.legal-displayed

处理动作

-print			#默认的处理动作,显示至屏幕
-prin0			#不换行输出,常用于配合xargs
-ls				#类似于对查找到的文件执行"ls -ils"命令格式输出
-fls file		#查找到的所有文件的长格式信息保存至指定文件中,相当于 -ls > file
-delete			#删除查找到的文件,慎用!
-ok COMMAND	{} \;	#对查找到的每个文件执行由COMMAND指定的命令,每个文件执行命令之前都会交互用户确认
-exec COMMAND {} \;	#对查找到的每个文件执行由COMMAND指定的命令
{}				#用于引用查找到的文件名称本身

#备份以log结尾的文件
find -name "*.log" -exec {} {}.bak \;
#删除15分钟内没被访问的文件
find -amin +15 -ok rm {} \;
#将other权限有w的文件的权限去掉w权限
find -perm -002 -exec chmod o-w {} \;

3) 文本处理三剑客之二

grep命令主要对文本的(正则表达式)行进行基于模式过滤

sed:stream editor,文本编辑器

awk:Linux上的实现gawk,文本报告生成器

grep

-c		#显示匹配的行数
-o		#仅显示匹配的内容
-q		#静默模式,通过echo $?判断是否成功
-A 2	        #显示匹配到的行和后2行
-B 2	        #显示匹配到的行和前2行
-C 2	        #前后都取
-r		#递归匹配,不处理软连接
-R		#递归匹配,处理软连接
-e		#使用多次-e指定多个模式
-E		#使用管道符|分割多个模式匹配
-l		#只显示匹配到的文件的文件名,不显示具体内容
-H		#显示内容来自哪个文件

取反

grep -v nologin /etc/passwd

取前三行

grep -m 3 bin /etc/passwd

不区分大小写

grep -i ROOT /etc/passwd

显示行号

grep -n bash /etc/passwd

静默模式

[root@ubuntu2204 ~]# grep -q root /etc/passwd
[root@ubuntu2204 ~]# echo $?
0
[root@ubuntu2204 ~]# grep -q qewqesda /etc/passwd
[root@ubuntu2204 ~]# echo $?
1

命令行展开

[root@ubuntu2204 ~]#  grep `whoami` /etc/passwd
root:x:0:0:root:/root:/bin/bash

变量展开

[root@ubuntu2204 ~]# grep $USER /etc/passwd
root:x:0:0:root:/root:/bin/bash

取CPU核数

[root@ubuntu2204 ~]# grep "process" /proc/cpuinfo 
processor   : 0
processor   : 1
processor   : 2
processor   : 3
[root@ubuntu2204 ~]# grep -c "process" /proc/cpuinfo
4
[root@ubuntu2204 ~]# grep -c "process" /proc/cpuinfo | wc -l
1

取分区最大利用率

[root@ubuntu2204 ~]# df | grep -E "^/dev" | tr -s " " "%" | cut -d"%" -f5 | sort -n | tail -1
14

sed

行编辑器

一行处理一行的设计模式使得sed性能很高,sed在读取大文件时不会出现卡顿的现象。 一行处理一行的设计模式使得sed性能很高,sed在读取大文件时不会出现卡顿的现象。

sed option script input-file
​
-n      #仅显示script处理后的结果
-r      #支持扩展表达式

script格式

'AddrCmd'   #地址命令,在哪些行,执行什么命令

地址格式

#为空,表示对全文处理#单地址,指定行
N       #具体行号
$       #最后一行
/pattern/   #能被匹配的每一行#范围地址
M,N     #第M行到第N行
M,+N    #第M行到第M+N行#步长
1~2     #奇数行
2~2     #偶数行

命令

p           #打印出匹配的内容,通过与-n选项配合使用
=           #只显示行号
d           #删除模式空间匹配的行,并启用下一轮循环,搭配-n无法显示内容
a []test   #在指定行后追加文本,支持使用\n实现多行追加
i []test   #行前插入
c []test   #替换行为单行或多行文本

范例

#匹配第一行
[root@ubuntu2204 ~]# sed -n '1p' passwd 
root:x:0:0:root:/root:/bin/bash
#匹配最后一行
[root@ubuntu2204 ~]# sed -n '$p' passwd 
lxd:x:999:100::/var/snap/lxd/common/lxd:/bin/false
#匹配指定内容
[root@ubuntu2204 ~]# sed -n '/bash/p' passwd 
root:x:0:0:root:/root:/bin/bash
czx:x:1000:1000:caizixin:/home/czx:/bin/bash
[root@ubuntu2204 ~]# grep "bash" passwd 
root:x:0:0:root:/root:/bin/bash
czx:x:1000:1000:caizixin:/home/czx:/bin/bash
#正则匹配,显示#开头的行号
[root@ubuntu2204 ~]# sed -n '/^#/=' /etc/fstab 
1
2
3
4
#行号开始,正则结束
[root@ubuntu2204 ~]# sed -n '8,/list/p' passwd 
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
​
[root@ubuntu2204 ~]# seq 10 | sed '1d;4d'
2
3
5
6
7
8
9
10
[root@ubuntu2204 test]# ifconfig ens33 | sed -En 's/.*inet (.*)  netmask.*/\1/p'
192.168.141.12

范例:添加内容

[root@ubuntu2204 ~]# cat test.txt 
aaa
bbb
ccc
ddd
#匹配行后插入 
[root@ubuntu2204 ~]# sed '/bbb/a---' test.txt 
aaa
bbb
---
ccc
ddd
#匹配行替换
[root@ubuntu2204 ~]# sed '/bbb/c---' test.txt 
aaa
---
ccc
ddd
#第一行替换成两行
[root@ubuntu2204 ~]# sed '1c\0000\n6666' test.txt 
0000
6666
bbb
ccc
ddd
#指定行前插入
[root@ubuntu2204 ~]# sed '2i---' test.txt 
aaa
---
bbb
ccc
ddd
[root@ubuntu2204 ~]# sed '2,4i---' test.txt 
aaa
---
bbb
---
ccc
---
ddd
# \的作用,界限的作用
[root@ubuntu2204 ~]# sed '1c      0000' test.txt 
0000
bbb
ccc
ddd
[root@ubuntu2204 ~]# sed '1c\  0000' test.txt 
  0000
bbb
ccc
ddd

范例:取ip行

[root@ubuntu2204 ~]# ifconfig ens33 | sed -n '/netmask/p'
        inet 192.168.141.128  netmask 255.255.255.0  broadcast 192.168.141.255
[root@ubuntu2204 ~]# ifconfig ens33 | head -n 2 | tail -1
        inet 192.168.141.128  netmask 255.255.255.0  broadcast 192.168.141.255
[root@ubuntu2204 ~]# ifconfig ens33 | sed -n '2p'
        inet 192.168.141.128  netmask 255.255.255.0  broadcast 192.168.141.255

范例:命令展开

[root@ubuntu2204 ~]# sed -n "/$(whoami)/p" passwd 
root:x:0:0:root:/root:/bin/bash
#第一行
[root@ubuntu2204 ~]# sed -n "$[$(id -u)+1]p" passwd 
root:x:0:0:root:/root:/bin/bash
[root@ubuntu2204 ~]# sed -n "$[`id -u`+1]p" passwd 
root:x:0:0:root:/root:/bin/bash
#倒数第二行
[root@ubuntu2204 ~]# sed -n "$[`cat /etc/passwd | wc -l`-1]p" passwd 
tom:x:1001:1001::/home/tom:/bin/sh

范例:变量展开

[root@ubuntu2204 ~]# num=1;sed -n "$num p" passwd 
root:x:0:0:root:/root:/bin/bash

范例:

^/dev/sd两个斜杠面前加\,整段前后加/
[root@ubuntu2204 ~]# df | sed -n '/^/dev/sd/p'
/dev/sda2                           1992552  258628   1612684  14% /boot

范例:不显示注释行和空行

#只显示#开头的行
[root@Rocky-1 ~]# sed -n '/^#/p' /etc/fstab 
#
# /etc/fstab
# Created by anaconda on Fri Jul  5 15:19:41 2024
#
# Accessible filesystems, by reference, are maintained under '/dev/disk/'.
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
#
# After editing this file, run 'systemctl daemon-reload' to update systemd
# units generated from this file.
##不显示注释行和空行
[root@Rocky-1 ~]# sed '/^#/d;/^$/d' fstab
[root@Rocky-1 ~]# sed -En '/^(#|$)/!p' fstab
​
​
​
#不显示注释行
[root@Rocky-1 ~]# sed -n '/^#/!p' fstab
​
/dev/mapper/rl-root     /                       xfs     defaults        0 0
UUID=79f753f0-e9da-4fa3-adf9-53f4df6a9782 /boot                   xfs     defaults        0 0
/dev/mapper/rl-home     /home                   xfs     defaults        0 0
/dev/mapper/rl-swap     none                    swap    defaults        0 0
​
[root@Rocky-1 ~]# sed -n '/^[^#]/p' fstab 
/dev/mapper/rl-root     /                       xfs     defaults        0 0
UUID=79f753f0-e9da-4fa3-adf9-53f4df6a9782 /boot                   xfs     defaults        0 0
/dev/mapper/rl-home     /home                   xfs     defaults        0 0
/dev/mapper/rl-swap     none                    swap    defaults        0 0
​

范例:修改文件

#修改前备份
[root@ubuntu2204 ~]# seq 10 > 10.txt
[root@ubuntu2204 ~]# sed -i.bak '2,7d' 10.txt 
[root@ubuntu2204 ~]# ls
10.txt  10.txt.bak  HPE_Linux  passwd  snap
[root@ubuntu2204 ~]# cat 10.txt
1
8
9
10#不备份
[root@ubuntu2204 ~]# sed -i '2,7d' 10.txt 

范例:删除注释行和空行

[root@Rocky-1 ~]# sed -i '/^#/d;/^$/d' fstab
[root@Rocky-1 ~]# sed -Ei '/^(#|$)/!p' fstab

范例:搜索替换和&(引用)

sed -n 's/root/ROOT/gp' passwd
sed -i 's/root/ROOT/g' passwd
​
#&引用前面的root
[root@ubuntu2204 ~]# sed -n 's/root/&ROOT/gp' passwd
rootROOT:x:0:0:rootROOT:/rootROOT:/bin/bash

范例:除指定文件外其余删除

#取非1357
[root@ubuntu2204 test]# ls | grep -Ev 'f-(1|3|5|7).txt'
f-10.txt
f-2.txt
f-4.txt
f-6.txt
f-8.txt
f-9.txt[root@ubuntu2204 test]# rm -rf `ls | grep -Ev 'f-(1|3|5|7).txt'`
​
[root@ubuntu2204 test]# ls | sed -n '/f-[^1357].txt/p'
f-2.txt
f-4.txt
f-6.txt
f-8.txt
f-9.txt

范例:获取分区利用率

#先找指定行
[root@ubuntu2204 test]# df | sed -En '/^/dev/sd/p'
/dev/sda2                           1992552  258628   1612684  14% /boot
#/dev.*匹配百分比前面的字符,空格接0-9+表示出现多次0到9,匹配百分比的数字,%匹配备份比,加起来就是利用率,%后.*匹配%后的字符,\1匹配引用()里面的[0-9]+。
df | sed -En 's/^\/dev.* ([0-9]+)%.*/\1/p'
​
[root@ubuntu2204 test]# df | sed -En 's/^\/dev.* ([0-9]+)%.*/\1/p' | sort -nr | head -1
14

范例:非#开头的行加#

sed -rn 's/^[^#]/#&/p' passwd
sed -ri 's/^[^#]/#&/p' passwd

范例:将#开头的行删除#

[root@ubuntu2204 ~]# sed Ei.bak '/^#/s/^#//' fstab

范例:替换selinux

[root@Rocky-1 ~]# sed -Ei.bak 's/^SELINUX=(.*)/SELINUX=enforcing/' config 
[root@Rocky-1 ~]# cat config# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
#     enforcing - SELinux security policy is enforced.
#     permissive - SELinux prints warnings instead of enforcing.
#     disabled - No SELinux policy is loaded.
SELINUX=enforcing
# SELINUXTYPE= can take one of these three values:
#     targeted - Targeted processes are protected,
#     minimum - Modification of targeted policy. Only selected processes are protected. 
#     mls - Multi Level Security protection.
SELINUXTYPE=targeted

4) 文本格式化命令

格式化输出printf

相当于增强版的echo,实现丰富的格式化输出

格式

printf format args..

说明

%[N]s       #N表示输出宽度,不够补空格,-N 表示左对齐%-10s
%[0][N]d    #0表示宽度不够时在左边补0,N表示输出宽度
%[.N]f      #.N表示保留的小数位

范例:

[root@ubuntu2204 bash-test]# printf "%s" 1 2 3 4
1234[root@ubuntu2204 bash-test]# printf "%s\n" 1 2 3 4
1
2
3
4
[root@ubuntu2204 bash-test]# printf "(%s)\n" 1 2 3 4
(1)
(2)
(3)
(4)

4. 总结文本处理的grep命令相关的基本正则和扩展正则表达式。

基本正则表达式

字符匹配

.			#匹配任意单个字符
[]			#匹配指定范围内的任意单个字符,[wang],[a-z],[a-zA-Z],[0-Z]
[^]			#匹配指定范围外的任意单个字符
[:alnum:]	#字母和数字
[:alpha:]	#表示任何大小写字符
[:lower:]	#小写字符
[:upper:]	#大写字符
[:blank:]	#空白字符(空格和制表符)
[:space:]	#包括空格、制表符、换行符回车符等

\s			#匹配任何空白字符
\S			#匹配任何非空字符
\w			#匹配一个字母、数字、下划线、汉字等字符
\W			#匹配一个非字母、数字、下划线、汉字等字符

匹配次数

用在要指定次数的字符后面,用于指定前面的字符要出现几次

*       #匹配前面的字符任意次,包括0次
.*      #任意长度的任意字符
?      #匹配其前面的字符出现0次或1次,可有可无
+      #匹配其前面的字符最少出现1次
{n}   #匹配前面的字符n次
{n,m} #匹配前面的字符n次,最多m次
{,n}  #匹配前面的字符最多n次
{n,}  #匹配前面的字符最少n次

范例

[root@ubuntu2204 ~]#  echo "rooot" | grep "ro*t"
rooot
[root@ubuntu2204 ~]# echo "rt" | grep "ro*t"
rt

范例:一次或多次

[root@ubuntu2204 ~]# echo "test" | grep "te+st"
test
[root@ubuntu2204 ~]# echo "tst" | grep "te+st"
[root@ubuntu2204 ~]# echo "teeest" | grep "te+st"
teeest

指定次数

[root@ubuntu2204 ~]# echo "teeest" | grep "te{1,3}st"
teeest
[root@ubuntu2204 ~]# echo "teeest" | grep "te{3}st"
teeest
[root@ubuntu2204 ~]# echo "teeest" | grep "te{1}st"
[root@ubuntu2204 ~]# 

取正负数

[root@ubuntu2204 ~]# cat 123.txt | grep "^[^-]"
1
2
3
5
6
[root@ubuntu2204 ~]# cat 123.txt | grep "^[-]"
-4
-7
-10
-15
[root@ubuntu2204 ~]# cat 123.txt | grep "^[0-9]"
1
2
3
5
6
[root@ubuntu2204 ~]# cat 123.txt | grep "^-[0-9]+"
-4
-7
-10
-15

位置锚定

用于定位出现的位置

^       #行首锚定
$       #行尾锚定
^$      #空行
​
[root@ubuntu2204 ~]# grep "^#" /etc/fstab 
# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point>   <type>  <options>       <dump>  <pass>
# / was on /dev/ubuntu-vg/ubuntu-lv during curtin installation
# /boot was on /dev/sda2 during curtin installation#非注释开头,非注释行
[root@ubuntu2204 ~]# grep "^[^#]" /etc/profile
#排除所有空行和注释行
grep -v '^$|^#' /etc/profile

分组其他

后向引用

[root@ubuntu2204 ~]# echo abc-def-abcabcabc-def-abc-defdef | grep "^(abc)-(def)-\1{3}-\2-\1-\2{2}"
abc-def-abcabcabc-def-abc-defdef
小括号表示分组
\1引用第一个分组abc
\2引用第二个分组def

或者

a|b        #ab
c|cat      #ccat
(C|c)cat  #Catcat[root@ubuntu2204 ~]# echo "12a" | grep "12a|b"
12a[root@ubuntu2204 ~]# echo "12ab" | grep -E "12a|b"
12ab
[root@ubuntu2204 ~]# echo "12ab" | grep "12a|b"
12ab
[root@ubuntu2204 ~]# echo "abc-xxx-xyz" | grep -E "[a-z]{3}-[a-z]{3}"
abc-xxx-xyz

5. sed将文件test中第50行中的helloworld改为nihao

先创建一个100行的文件做测试

[root@ubuntu2204 ~]# seq 1 100 > test

sed筛选第50行,将第50行内容变为包含helloworld的内容

[root@ubuntu2204 ~]# sed -n '50p' test
50
[root@ubuntu2204 ~]# sed -i '50c\yes hello helloworld' test
[root@ubuntu2204 ~]# sed -n '50p' test
yes hello helloworld

最后将第50行的helloworld改为nihao

[root@ubuntu2204 ~]# sed -i '50s/helloworld/nihao/g' test
[root@ubuntu2204 ~]# sed -n '50p' test
yes hello nihao

6. 在每一行后增加一空行

测试文件为cp /etc/passwd ~/,不要直接修改passwd文件

#将结束符替换成回车
[root@ubuntu2204 ~]# sed -i 's/$/\n/' passwd
[root@ubuntu2204 ~]# cat passwd 
root:x:0:0:root:/root:/bin/bash

daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin

bin:x:2:2:bin:/bin:/usr/sbin/nologin

...

#第二种方法是sed自带的动作
[root@ubuntu2204 ~]# sed 'G' passwd 
root:x:0:0:root:/root:/bin/bash

daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin

bin:x:2:2:bin:/bin:/usr/sbin/nologin

sys:x:3:3:sys:/dev:/usr/sbin/nologin


7.删除文件每行的第一个字符。

[root@ubuntu2204 ~]# cat test.txt 
root
ROOT
[root@ubuntu2204 ~]# sed 's/^.//' test.txt 
oot
OOT

[root@ubuntu2204 ~]# sed -r 's/(.)(.*)/\2/' test.txt 
oot
OOT

8.删除文件每行的第二个字符。

[root@ubuntu2204 ~]# sed -r 's/(.)(.)(.*)/\2/' test.txt 
o
O
[root@ubuntu2204 ~]# sed -r 's/(.)(.)(.*)/\1\3/' test.txt 
rot
ROT
[root@ubuntu2204 ~]# sed -r 's/(.)(.)(.*)/\1\2/' test.txt 
ro
RO

9.删除文件每行的最后一个字符。

[root@ubuntu2204 ~]# sed -r 's/(.)(.*)(.$)/\3/' test.txt 
t
T
[root@ubuntu2204 ~]# sed -r 's/(.)(.*)(.$)/\1\2/' test.txt 
roo
ROO

10.删除文件每行的倒数第二个字符

[root@ubuntu2204 ~]# sed -r 's/(.)(.*)(.)(.$)/\3/' test.txt 
o
O
[root@ubuntu2204 ~]# sed -r 's/(.)(.*)(.)(.$)/\1\2\4/' test.txt 
rot
ROT

11. 总结变量命名规则,不同类型变量(环境变量,位置变量,只读变量,局部变量,状态变量)如何使用。

变量命名规则

命名要求:
​	区分大小写
​	不能使用程序的保留字和内置变量
​	只能使用数字、字母及下划线,且不能以数字开头

命名习惯:
​	用英文单词命名,体现出实际作用
​	变量名大写
​	局部变量小写
​	函数名小写
​	大驼峰StudentFirstName
​	小驼峰studentFirstName
​	下划线:student_first_name

变量的定义和引用

变量的生效范围等标准划分变量类型
​	普通变量:生效范围为当前shell进程;对当前shell以外的其它shell进程,包括当前shell的子进程无效
​	环境变量:生效范围为当前shell进行及其子进程
​	本地变量:生效范围为当前shell进程中某代码片段,通常指函数

name='root'	#字符串赋值给name
name="$USER"	#变量引用赋值
name=`COMMAND`	#命令引用
name=$(COMMAND)	#命令引用

[root@ubuntu2204 ~]# name="$USER"_123;echo $name
root_123

环境变量

环境变量

可以使子进程(包括孙子进程)继承父进程的变量,但是无法让父进程使用子进程的变量

一旦子进程修改从父进程继承的变量,将会将新的值传递给孙子进程

一般只在系统配置文件中使用,在脚本中较少使用 变量声明和赋值:

#声明并赋值
export name = VALUE
declare -x name=VALUE
​
#或者分两步实现
name=VLAUE
export name

显示所有的环境变量

env
printenv
export
declare -x

只读变量

只能声明定义,但后续不能修改和删除,即常量

声明只读变量

readonly name
declare -r name

查看只读变量

readonly [-p]
declare -r

范例

[root@ubuntu2204 ~]# readonly testname="czx"
[root@ubuntu2204 ~]# echo $testname 
czx
[root@ubuntu2204 ~]# unset testname
bash: unset: testname: cannot unset: readonly variable

位置变量

在bash shell中内置的变量,在脚本代码中调用通过命令行传递给脚本的参数

$1,$2...        #对应脚本的第一个,第二个参数
$0              #命令本身,包括路径
$*              #传递给脚本的所有参数,全部参数合为一个字符串
$@              #传递给脚本的所有参数,每个参数为独立字符串
$#              #传递给脚本的参数的个数

清空所有位置变量

set --

范例:

[root@ubuntu2204 ~]# cat args.sh
echo "1st arg is $1"
echo "2st arg is $2"
echo "3st arg is $3"
#不写{}会解析成$1加0
echo "10st arg is ${10}"echo "all arg is $*"echo "arg numbers is $#"
[root@ubuntu2204 ~]# bash args.sh 123 321 1234
1st arg is 123
2st arg is 321
3st arg is 1234
all arg is 123 321 1234
arg numbers is 3

范例:*和@的区别

[root@ubuntu2204 ~]# cat arg-test.sh 
#!/bin/bash
echo 'This is $@'
for i in "$@";do
    echo $i;
done
echo 'This is $*'
for i in "$*";do
    echo $i;
done
[root@ubuntu2204 ~]# bash arg-test.sh {A..D}
This is $@
A
B
C
D
This is $*
A B C D

状态变量

当我们浏览网页时,有时会看到404,503等错误信息就是状态码,shell中也有表示脚本执行状态的技术。

进程执行后,将使用变量$?存放状态码的相关数字,不同的值反应成功或失败

$?      #0表示成功,1-255表示失败#脚本中用exit来定义状态码,脚本的状态码取决于最后一条命令或者exit后的数字
#脚本执行到exit就会立即终止
exit 123

12. 通过shell编程完成,30鸡和兔的头,80鸡和兔的脚,分别有几只鸡,几只兔?

第一种实现

[root@ubuntu2204 shell]# cat chook_rabbit.sh 
#!/bin/bash

HEAD=$1
FOOT=$2

RABBIT=$[($FOOT-$HEAD-$HEAD)/2]
CHOOK=$[HEAD-RABBIT]
echo RABBIT:$RABBIT
echo CHOOK:$CHOOK

[root@ubuntu2204 shell]# bash chook_rabbit.sh 30 80
RABBIT:10
CHOOK:20

第二种实现

[root@ubuntu2204 shell]# cat chook_rabbit2.sh 
#!/bin/bash

HEAD=$1
FOOT=$2

for ((Ck_head = 0;Ck_head <= $HEAD;Ck_head++))
do
	Rab_head=$(($HEAD - $Ck_head))
	Ck_foot=$((2 * $Ck_head))
	Rab_foot=$((4 * $Rab_head))
	if [ $(( $Ck_foot + $Rab_foot )) -eq $FOOT ]
	then
		echo "Kunkun has $Ck_head,Rabbit has $Rab_head"
		continue
	fi
	#echo $Rab_head
done

[root@ubuntu2204 shell]# bash chook_rabbit2.sh 30 80
Kunkun has 20,Rabbit has 10
[root@ubuntu2204 shell]# bash chook_rabbit2.sh 35 94
Kunkun has 23,Rabbit has 12

13. 结合编程的for循环,条件测试,条件组合,完成批量创建100个用户,

1)for遍历1..100 2)先id判断是否存在 3)用户存在则说明存在,用户不存在则添加用户并说明已添加。

[root@ubuntu2204 shell]# cat User_create.sh 
#!/bin/bash

for ((num = 1;num <= 100;num++))
do
	User_create="User$num"
	id $User_create &>/dev/null
	if [ $? != 0 ]
	then
		useradd $User_create
		if [ $? == 0 ]
		then
			echo "$User_create is create success"
		else
			echo "$User_create is create fail"
		fi
	else
		echo "$User_create is exist"
	fi	      
	#echo $User_create
done
[root@ubuntu2204 shell]# bash User_create.sh 
User1 is create success
User2 is create success
User3 is create success
User4 is create success
User5 is create success
User6 is create success
...

#如果用户存在则不会创建
[root@ubuntu2204 shell]# bash User_create.sh 
User1 is exist
User2 is exist
User3 is exist
User4 is exist
User5 is exist
User6 is exist
User7 is exist

实验结束再将用户批量删除

[root@ubuntu2204 shell]# cp User_create.sh User_del.sh
#将创建脚本的useradd改为userdel
[root@ubuntu2204 shell]# cat User_del.sh 
#!/bin/bash

for ((num = 1;num <= 100;num++))
do
	User_del="User$num"
	id $User_del &>/dev/null
	if [ $? == 0 ]
	then
		userdel $User_del
		if [ $? == 0 ]
		then
			echo "$User_del is delete success"
		else
			echo "$User_del is delete fail"
		fi
	else
		echo "$User_del is not exist"
	fi	      
done

[root@ubuntu2204 shell]# bash User_del.sh 
User1 is delete success
User2 is delete success
User3 is delete success
...
[root@ubuntu2204 shell]# bash User_del.sh 
User1 is not exist
User2 is not exist
User3 is not exist
User4 is not exist
...