一、文件权限管理
1.1 UGO权限管理
1.1.1 权限介绍
在Linux系统中,权限有3种:读权限、写权限、执行权限,分别用字母r、w、x表示
一个文件的权限可以分为3类不同的用户:文件属主用户、组用户、其他用户,分别用字母u、g、o表示。
可以分别使用以下命令查看文件权限。
ll可看到文件的具体描述信息,其中最左边一列除第一位代表文件类型外,后9位代表文件权限。其中前三位是属主权限,中间三位是属组用户权限,最后三位是其他用户权限。r、w、x分别表示读、写和执行权限,显示-说明没有该权限。
stat命令也可以看到文件的权限,该权限是采用数字表示。
那么为什么这个文件的权限用数字表示是644呢?首先,权限可以用分别用三位二进制数表示,读表示最高位,写表示中间位,执行表示最后一位,这样得到的权限与数字的对应关系如下(0表示无权限,1表示有权限):
读 | 写 | 执行 | 二进制数 | 十进制数 |
0 | 0 | 0 | 000 | 0 |
0 | 0 | 1 | 001 | 1 |
0 | 1 | 0 | 010 | 2 |
0 | 1 | 1 | 011 | 3 |
1 | 0 | 0 | 100 | 4 |
1 | 0 | 1 | 101 | 5 |
1 | 1 | 0 | 110 | 6 |
1 | 1 | 1 | 111 | 7 |
当权限数字表示为6时,对应的权限就是具有读写权限,而没有执行权限。而一个文件权限的三位数字,从左到右分别为属主权限,组用户权限和其他用户权限。
这样,上例中文件 1.txt ,属主权限是读写,组用户权限是读,其他用户权限是写,对应的权限用数字表示就是644。
1.1.2 修改文件权限
使用 chmod 命令可以修改文件权限
[root@rocky dir1]# ll 1.txt
-rw-r--r--. 1 root root 0 Aug 4 17:52 1.txt
# 修改文件权限777
[root@rocky dir1]# chmod 777 1.txt
[root@rocky dir1]# ll 1.txt
-rwxrwxrwx. 1 root root 0 Aug 4 17:52 1.txt
# 移除其他用户的所有权限
[root@rocky dir1]# chmod o= 1.txt
[root@rocky dir1]# ll 1.txt
-rwxrwx---. 1 root root 0 Aug 4 17:52 1.txt
# 所有用户添加执行权限
[root@rocky dir1]# chmod +x 1.txt
[root@rocky dir1]# ll 1.txt
-rwxrwx--x. 1 root root 0 Aug 4 17:52 1.txt
# 移除组用户的写和执行权限
[root@rocky dir1]# chmod g-wx 1.txt
[root@rocky dir1]# ll 1.txt
-rwxr----x. 1 root root 0 Aug 4 17:52 1.txt
# 修改属主用户权限为读写权限
[root@rocky dir1]# chmod u=rw 1.txt
[root@rocky dir1]# ll 1.txt
-rw-r----x. 1 root root 0 Aug 4 17:52 1.txt
1.2 文件属性
1.2.1 文件属性介绍
查看文件属性主要有两种命令,ll和stat
ll命令查看文件属性:
stat查看文件属性:
属性名 | 描述 |
File | 文件名 |
Size | 大小 |
Blocks | 文件所占的块数 |
IO Block | 块大小 |
regular empty file | 文件类型 |
Device | 设备编号 |
Inode | inode编号 |
Links | 链接数 |
Access | 文件权限 |
Uid | 文件所有者的ID |
Gid | 文件所属组的ID |
Access | 文件最后访问时间 |
Modify | 文件内容最后修改时间 |
Change | 文件属性最后修改时间 |
一般当文件内容修改时,modify和change属性都会刷新时间,因为一般文件内容改变文件大小也会跟着变。
1.2.2 文件属性改变
chown 改变文件所有者及所属组
[root@rocky dir1]# ll 1.txt
-rw-r----x. 1 root root 0 Aug 4 17:52 1.txt
# 改变文件所有者
[root@rocky dir1]# chown njn 1.txt
[root@rocky dir1]# ll 1.txt
-rw-r----x. 1 njn root 0 Aug 4 17:52 1.txt
# 改变文件所属组
[root@rocky dir1]# chown .njn 1.txt
[root@rocky dir1]# ll 1.txt
-rw-r----x. 1 njn njn 0 Aug 4 17:52 1.txt
# 同时改变文件所属主和属组
[root@rocky dir1]# chown tom.tom 1.txt
[root@rocky dir1]# ll 1.txt
-rw-r----x. 1 tom tom 0 Aug 4 17:52 1.txt
chgrp 改变文件所属组
[root@rocky dir1]# ll 2.txt
-rw-r--r--. 1 root root 0 Aug 4 17:52 2.txt
[root@rocky dir1]# chgrp njn 2.txt
[root@rocky dir1]# ll 2.txt
-rw-r--r--. 1 root njn 0 Aug 4 17:52 2.txt
1.3 文件默认权限
可通过umask查看默认权限掩码:
[root@rocky dir1]# umask
0022
umask第一位先不作介绍,后三位是文件权限的掩码。新建文件的权限就是666减去umask后三位,新建目录的权限是777减去umask后三位。
比如,现在umask是0022,新建文件权限是644,新建目录权限是755。
[root@rocky dir1]# mkdir da
[root@rocky dir1]# touch a
[root@rocky dir1]# ll
total 0
-rw-r--r--. 1 root root 0 Aug 6 23:00 a
drwxr-xr-x. 2 root root 6 Aug 6 23:00 da
可以使用 umask [UMASK] 命令改变umask值
[root@rocky dir1]# umask 0033
[root@rocky dir1]# umask
0033
1.4 访问控制列表ACL
ACL可以提供更颗粒度的权限,比如,单独把文件的写权限授予某个用户等。
查看默认情况下文件的ACL规则:
[root@rocky dir1]# getfacl a
# file: a
# owner: root
# group: root
user::rw-
group::r--
other::r--
使用 setfacl 添加文件的ACL规则:
# 设置njn用户没有权限
[root@rocky dir1]# setfacl -m u:njn:--- a
[root@rocky dir1]# getfacl a
# file: a
# owner: root
# group: root
user::rw-
user:njn:---
group::r--
mask::r--
other::r--
# 无法访问文件
[root@rocky dir1]# su njn -c 'cat a'
cat: a: Permission denied
删除文件的ACL规则
# 移除所有给njn用户设置的ACL规则
[root@rocky dir1]# setfacl -x u:njn a
[root@rocky dir1]# getfacl a
# file: a
# owner: root
# group: root
user::rw-
group::r--
mask::r--
other::r--
# 移除所有ACL规则
[root@rocky dir1]# setfacl -b a
[root@rocky dir1]# getfacl a
# file: a
# owner: root
# group: root
user::rw-
group::r--
other::r--
mask权限只影响除所有者和其他人之外的人和组的权限,其中ACL规则中设置的权限必须与mask权限进行逻辑与计算后,才能得到最终的权限。用户的权限必须在mask权限设置范围内才能生效。
比如,mask::rw-,不管ACL规则是否给用户设置执行权限,该用户均不具有执行权限。
二、文本编辑工具vim的常见操作
vim打开文件。
[root@rocky dir1]# vim a
在打开文件后为命令模式,按下:进入扩展命令模式,然后按下q再按回车执行退出vim命令。
~
~
~
~
:q
vim打开文件后,按i进入编辑模式,可以自由编辑文件。
# vim文件内,按i进入插入模式,编辑文本
dia
diaq
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
-- INSERT --
编辑完成后按esc键退回到命令模式。然后按:进入扩展命令模式,执行wq保存并退出文件
# 扩展命令模式执行wq退出文件
dia
diaq
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
:wq
cat查看文件可看到内容发生改变
[root@rocky dir1]# cat a
dia
diaq
在命令模式有以下几种常见的操作
w # 跳转到下一单词词首
e # 跳转到当前单词或下一单词词尾
b # 跳转到当前或上一单词词首
dd # 删除光标所在行
ndd # n是数字,表示删除从当前行开始的n行
yy # 复制当前行
nyy # 复制从当前行开始的n行
p # 在当前行下方粘贴
P # 在当前行上方粘贴
三、文本处理与查找
3.1 文本处理
cat 命令可以查看文件,主要用法如下:
cat -E a # 显示文本行末字符
cat -A a # 显示所有控制符
cat -n a # 显示所有行号
cat -b a # 非空行编号
cat -s a # 所有空行压缩成一行
hexdump可以显示按照字节码显示文件
[root@rocky dir1]# hexdump a
0000000 6964 7161 6420 7369 2061 7164 7020 656f
0000010 6420 6169 0a0a 6964 6320 207a 6971 7720
0000020 7065 206f 736c 2069 6963 440a 4149 204f
0000030 4945 4f41 4520 0a53 6964 7161 6420 7369
0000040 2061 7164 7020 656f 6420 6169 0a0a 6964
0000050 2061 6975 6975 6120 206c 6378 640a 2069
0000060 7a63 7120 2069 6577 6f70 6c20 6973 6320
0000070 0a69 6964 7161 6420 7369 2061 7164 7020
0000080 656f 6420 6169 640a 2069 7a63 7120 2069
0000090 6577 6f70 6c20 6973 6320 0a69 6964 7161
00000a0 6420 7369 2061 7164 7020 656f 6420 6169
00000b0 090a 6964 7161 6420 7369 2061 7164 7020
00000c0 656f 6420 6169 000a
00000c7
# 一个字节一个单词
[root@rocky dir1]# hexdump -C a
00000000 64 69 61 71 20 64 69 73 61 20 64 71 20 70 6f 65 |diaq disa dq poe|
00000010 20 64 69 61 0a 0a 64 69 20 63 7a 20 71 69 20 77 | dia..di cz qi w|
00000020 65 70 6f 20 6c 73 69 20 63 69 0a 44 49 41 4f 20 |epo lsi ci.DIAO |
00000030 45 49 41 4f 20 45 53 0a 64 69 61 71 20 64 69 73 |EIAO ES.diaq dis|
00000040 61 20 64 71 20 70 6f 65 20 64 69 61 0a 0a 64 69 |a dq poe dia..di|
00000050 61 20 75 69 75 69 20 61 6c 20 78 63 0a 64 69 20 |a uiui al xc.di |
00000060 63 7a 20 71 69 20 77 65 70 6f 20 6c 73 69 20 63 |cz qi wepo lsi c|
00000070 69 0a 64 69 61 71 20 64 69 73 61 20 64 71 20 70 |i.diaq disa dq p|
00000080 6f 65 20 64 69 61 0a 64 69 20 63 7a 20 71 69 20 |oe dia.di cz qi |
00000090 77 65 70 6f 20 6c 73 69 20 63 69 0a 64 69 61 71 |wepo lsi ci.diaq|
000000a0 20 64 69 73 61 20 64 71 20 70 6f 65 20 64 69 61 | disa dq poe dia|
000000b0 0a 09 64 69 61 71 20 64 69 73 61 20 64 71 20 70 |..diaq disa dq p|
000000c0 6f 65 20 64 69 61 0a |oe dia.|
000000c7
# 显示前20个字节
[root@rocky dir1]# hexdump -C -n 20 a
00000000 64 69 61 71 20 64 69 73 61 20 64 71 20 70 6f 65 |diaq disa dq poe|
00000010 20 64 69 61 | dia|
00000014
more可以分页显示文件,在文件页面按空格可跳转,按回车可跳到下一行,按q可退出,按h可显示帮助信息。
[root@rocky dir1]# more /etc/passwd
# more 显示的文件信息
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
systemd-coredump:x:999:997:systemd Core Dumper:/:/sbin/nologin
systemd-resolve:x:193:193:systemd Resolver:/:/sbin/nologin
tss:x:59:59:Account used for TPM access:/dev/null:/sbin/nologin
polkitd:x:998:996:User for polkitd:/:/sbin/nologin
unbound:x:997:995:Unbound DNS resolver:/etc/unbound:/sbin/nologin
geoclue:x:996:994:User for geoclue:/var/lib/geoclue:/sbin/nologin
rtkit:x:172:172:RealtimeKit:/proc:/sbin/nologin
pipewire:x:995:991:PipeWire System Daemon:/var/run/pipewire:/sbin/nologin
pulse:x:171:171:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin
qemu:x:107:107:qemu user:/:/sbin/nologin
clevis:x:994:988:Clevis Decryption Framework unprivileged user:/var/cache/clevis:/sbin/nologin
usbmuxd:x:113:113:usbmuxd user:/:/sbin/nologin
gluster:x:993:987:GlusterFS daemons:/run/gluster:/sbin/nologin
rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin
avahi:x:70:70:Avahi mDNS/DNS-SD Stack:/var/run/avahi-daemon:/sbin/nologin
--More--(60%)
包括less命令也可以分页查看文件内容。
head可以显示文件的前几行
# 默认显示前10行
[root@rocky dir1]# head /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
# 显示文件前2行
[root@rocky dir1]# head -n 2 /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
[root@rocky dir1]# head -2 /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
# 获取前6字节
[root@rocky dir1]# head -c 6 /etc/passwd
root:x[root@rocky dir1]#
# 获取从头行开始到倒数第33行
[root@rocky dir1]# cat -n /etc/passwd | head -n -32
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8 halt:x:7:0:halt:/sbin:/sbin/halt
9 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
10 operator:x:11:0:operator:/root:/sbin/nologin
11 games:x:12:100:games:/usr/games:/sbin/nologin
12 ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
13 nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin
tail与head相反,相关用法不再详细描述。有一个常见用法是 tail -f,可以开启一个进程实时显示最新输出到文件的信息,通常用于日志分析。
[root@rocky dir1]# tail -f /var/log/messages
Aug 8 15:16:10 rocky NetworkManager[1167]: <info> [1723101370.7460] dhcp4 (ens160): state changed new lease, address=192.168.206.133
Aug 8 15:31:10 rocky NetworkManager[1167]: <info> [1723102270.7490] dhcp4 (ens160): state changed new lease, address=192.168.206.133
Aug 8 15:46:10 rocky NetworkManager[1167]: <info> [1723103170.7458] dhcp4 (ens160): state changed new lease, address=192.168.206.133
Aug 8 16:01:10 rocky NetworkManager[1167]: <info> [1723104070.7468] dhcp4 (ens160): state changed new lease, address=192.168.206.133
Aug 8 16:09:34 rocky systemd[1]: Starting dnf makecache...
Aug 8 16:09:35 rocky dnf[42757]: Metadata cache refreshed recently.
Aug 8 16:09:35 rocky systemd[1]: dnf-makecache.service: Succeeded.
Aug 8 16:09:35 rocky systemd[1]: Started dnf makecache.
Aug 8 16:16:10 rocky NetworkManager[1167]: <info> [1723104970.7465] dhcp4 (ens160): state changed new lease, address=192.168.206.133
Aug 8 16:31:10 rocky NetworkManager[1167]: <info> [1723105870.7461] dhcp4 (ens160): state changed new lease, address=192.168.206.133
cut可以分割文本的每一行,显示相应的内容
# 按照:分割,显示前3列
[root@rocky dir1]# cut -d: -f1-3 /etc/passwd -s | head -3
root:x:0
bin:x:1
daemon:x:2
wc可以统计文本的行数,字节数,单词数
[root@rocky dir1]# wc /etc/passwd
45 103 2504 /etc/passwd
行数 单词数 字节数
# 行数
[root@rocky dir1]# cat /etc/passwd | wc -l
45
# 单词数
[root@rocky dir1]# cat /etc/passwd | wc -w
103
# 字节数
[root@rocky dir1]# cat /etc/passwd | wc -c
2504
# 字符数
[root@rocky dir1]# cat /etc/passwd | wc -m
2504
# 最长行的长度
[root@rocky dir1]# cat /etc/passwd | wc -L
94
sort可以对文本排序,默认情况下先按照第一个字符排,再按照第二个字符排。常见用法如下:
-r # 倒序
-b # 忽略空白字符
-f # 忽略大小写
-n # 按照数字大小排序
-t # 指定列分隔符
-k # 指定排序列
-u # 去重
uniq可以对文本去重,具体用法如下:
[root@rocky dir1]# sort a
DIAO EIAO ES
diaq disa dq poe dia
diaq disa dq poe dia
diaq disa dq poe dia
diaq disa dq poe dia
diaq disa dq poe dia
dia uiui al xc
di cz qi wepo lsi ci
di cz qi wepo lsi ci
di cz qi wepo lsi ci
# 显示每行出现次数
[root@rocky dir1]# sort a | uniq -c
3
1 DIAO EIAO ES
1 diaq disa dq poe dia
4 diaq disa dq poe dia
1 dia uiui al xc
3 di cz qi wepo lsi ci
# 只显示重复出现的行一次
[root@rocky dir1]# sort a | uniq -d
diaq disa dq poe dia
di cz qi wepo lsi ci
# 只显示重复出现的行
[root@rocky dir1]# sort a | uniq -D
diaq disa dq poe dia
diaq disa dq poe dia
diaq disa dq poe dia
diaq disa dq poe dia
di cz qi wepo lsi ci
di cz qi wepo lsi ci
di cz qi wepo lsi ci
# 只显示没有重复出现的行
[root@rocky dir1]# sort a | uniq -u
DIAO EIAO ES
diaq disa dq poe dia
dia uiui al xc
diff可以比较文本
[root@rocky dir1]# cat diff1
222
xx
njn
haha
[root@rocky dir1]# cat diff2
xx
njn
lala
haha
[root@rocky dir1]# diff diff1 diff2
1d0
< 222
3a3
> lala
# 按照某种格式显示文本差异
[root@rocky dir1]# diff -u diff1 diff2
--- diff1 2024-08-08 17:20:09.300034574 +0800
+++ diff2 2024-08-08 17:21:04.488035450 +0800
@@ -1,4 +1,4 @@
-222
xx
njn
+lala
haha
3.2 文件查找
常见的文件查找命令有locate和find,两者区别主要在于,locate是非实时查找,find是实时查找。
3.2.1 locate
locate是直接依据系统上预建的文件索引数据库中的内容来查找。其更新是一个定时任务,一段时间执行一次。因此是非实时查找,如果要确保查找的实时性则需要先执行 updatedb 命令更新数据库。但该命令由于已建立数据库,查找速度快。
3.2.2 find
重点来说说最常用的文件查找命令find。find是一种实时查找,执行命令时会从指定目录根据文件系统查找符合条件的文件。
find 命令格式如下:
find [选项] [查找路径] [查找条件] [执行动作]
find 默认的查询路径是当前目录,会递归地查询当前目录及所有子目录下的文件。
# 当前目录结构
[root@rocky dir1]# tree
.
├── a
├── abash.sh
└── da
├── 1.txt
└── 2.txt
1 directory, 4 files
# find查询结果
[root@rocky dir1]# find
.
./.aa
./da
./da/1.txt
./da/2.txt
./a
./abash.sh
查询条件主要有以下几种:
-maxdepth N # 目录最大深度N
-mindepth N # 目录最小深度N
-name # 按照文件名查找
-path # 指定目录下的文件
-regex # 按照正则表达式匹配整个文件路径
-user # 指定所有者
-group # 指定属组
-uid # 指定所有者ID
-gid # 指定组ID
-nouser # 没有用户
-nogroup # 没有组
-type # 文件类型,包括目录d,普通文件f等
-empty # 空文件或空目录
# 根据大小查找
-size +10k # (10k,^)
-size 10k # (9k,10k]
-size -10k # [0k,9k]
# 根据文件时间戳查找
-atime +5 # 上次访问5天前
-mtime -5 # 5天内修改过内容
-ctime +10 # 上次修改属性10天前
-amin +5 # 上次访问5分钟前
-mmin -5 # 5分钟内修改过内容
-cmin +10 # 上次修改属性10分钟前
-perm # 根据权限查找
# 逻辑运算符
-a # 且
-o # 或
not | ! # 非
# 查看当前目录下的目录或名称以.txt结尾的普通文件
[root@rocky dir1]# find \( -type d -o -name *.txt \)
.
./da
./da/1.txt
./da/2.txt
常见处理动作:
-print # 默认的处理动作,输出至屏幕
-print0 # 使用\0代替换行符,通常配合 xargs -0
-ls # 列出文件的详细信息
-delete # 删除文件
# {} 用于引用查找到的文件自身
-exec COMMAND {} \; # 对每个文件执行COMMAND命令
-ok COMMAND {} \; # 对每个文件执行COMMAND命令,在执行前交互式确认
# 查找文件并将找到的符合要求的文件复制到/tmp/dir2
[root@rocky da]# mkdir /tmp/dir2
[root@rocky da]# find -name "*.txt" -exec cp {} /tmp/dir2 \;
[root@rocky da]# ll /tmp/dir2
total 0
-rw-r--r--. 1 root root 0 Aug 8 19:47 1.txt
-rw-r--r--. 1 root root 0 Aug 8 19:47 2.txt
通常与xargs配合使用:
[root@rocky da]# cat 1.txt
aaa#root/ididndiaoroot
1122
[root@rocky da]# cat 2.txt
aaa#rot/idrootndoroot
3434
[root@rocky da]# find -name "*.txt" | xargs grep root
./1.txt:aaa#root/ididndiaoroot
./2.txt:aaa#rot/idrootndoroot
3.3 文本格式化打印print
print命令可以格式化打印文本,主要用法如下:
# 命令用法
print [format] [args] ...
# 常见替换符
%s # 字符串
%d # 十进制数
%x # 十六进制数
%o # 八进制数
%f # 浮点数
%.2f # 保留2位小数的浮点数
%4d # 占据4个字符,右对齐
%-4d # 占据4个字符,左对齐
# 用法示例
[root@rocky da]# printf "%s.aaa\n" 2 3 4 5
2.aaa
3.aaa
4.aaa
5.aaa
[root@rocky da]# printf "%4d haha\n" 5 6 7
5 haha
6 haha
7 haha
[root@rocky da]# printf "%-4d haha\n" 5 6 7
5 haha
6 haha
7 haha
3.4 文本处理三剑客
3.4.1 grep
grep命令用于查找文件里面的字符串,主要用法如下:
-E # 支持扩展正则,同egrep
-e # 取并集,如 `grep -e aaa -e bbb` 表示查找包含aaa或bbb的行
-v # 取反,显示不包含匹配的内容的行
-i # 忽略大小写
-h # 不显示文件名
-H # 显示文件名
-n # 显示行号
-r # 递归地查找文件匹配字符串(默认只在当前目录查找文件)
-R # 同 -r,但支持软链接
-l # 只显示文件名
-q # 静默模式,不显示内容(与 echo $? 配合使用)
-A N # 显示匹配行及后N行
-B N # 显示匹配行及前N行
-C N # 显示匹配行及前后N行
3.4.2 sed
sed命令通常可用于匹配文本并打印,替换文本的字符串,插入文本等,通常用法如下:
[root@rocky da]# cat test1
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
# 输出第一行至第三行,p表示输出,-n表示不自动打印(正常情况下每扫描一行都会打印)
[root@rocky da]# sed -n '1,3p' test1
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
# 只输出第一行,$表示最后一行,d表示删除
[root@rocky da]# sed '2,$d' test1
root:x:0:0:root:/root:/bin/bash
# 匹配mail开头的行并打印
[root@rocky da]# sed -n '/^mail/p' test1
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
# 将所有的root替换为ROOT并输出
[root@rocky da]# sed 's/root/ROOT/g' test1
ROOT:x:0:0:ROOT:/ROOT:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/ROOT:/sbin/nologin
# -i命令会替换原文件内容
[root@rocky da]# sed -i 's/root/ROOT/g' test1
[root@rocky da]# cat test1
ROOT:x:0:0:ROOT:/ROOT:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/ROOT:/sbin/nologin
3.4.3 awk
awk命令通常用于文本的匹配查询并输出相应内容
[root@rocky da]# cat test1
ROOT:x:0:0:ROOT:/ROOT:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/ROOT:/sbin/nologin
# 以:为分隔符,匹配第三行并输出由分隔符分割的第一列和第三列数据
[root@rocky da]# awk -F: 'NR==3{print $1,$3}' test1
daemon 2
# 以:为分隔符,打印第一列为"bin"的那一列数据的第二列和第四列
[root@rocky da]# awk -F: '$1=="bin"{print $2,$4}' test1
x 1
四、正则表达式
4.1 基本正则表达式
字符匹配:
. # 匹配任意一个字符
[] # 匹配[]范围内任意一个字符,[]可以是a到z的任意一个字符[a-z], wang的任意一个字符[wang], 除wang的任意一个字符[^wang]
\s # 任意空白字符
\S # 任意非空白字符
\w # 字母、数字或下划线
\w # 除字母、数字或下划线以外的内容
匹配次数:
* # 前面的字符0次或多次
.* # 任意长度字符串
\? # 0次或1次
\+ # 一次或多次
\{n} # n次
\{m,n\} # 最少m次,最多n次
\{m,\} # 最少m次
\{,n\} # 最多n次
位置:
^ # 匹配开头
$ # 匹配结尾
^$ # 匹配空行
\< # 匹配单词开头
\> # 匹配单词结尾
\<[PATTERN]>\ #匹配单词
分组:
可以使用()来捕获分组,然后使用{m}等符号匹配某个分组出现多次,且可\1, \2引用捕获的分组,具体案例如下:
4.2 扩展正则表达式
扩展正则表达式就是基本正则表达式把所有带有\的符号都去除\即可,无需刻意去记忆。
五、文本处理常见案例
注意:以下命令均省略了-i选项,如果要修改文件则加上-i选项
sed将文件test中第50行中的helloworld改为nihao。
# 修改前第50行
[root@rocky da]# sed -n '50p' test
helloworld:x:1000:1000:helloworld:/home/njn:/bin/bash
# 修改
[root@rocky da]# sed -i.bak '50s/helloworld/nihao/g' test
# 修改后第50行
[root@rocky da]# sed -n '50p' test
nihao:x:1000:1000:nihao:/home/njn:/bin/bash
在每一行后增加一空行,测试文件为cp /etc/passwd ~/。
[root@rocky dir1]# sed G passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
...
删除文件每行的第一个字符。
[root@rocky dir1]# sed 's/.//' passwd
oot:x:0:0:root:/root:/bin/bash
in:x:1:1:bin:/bin:/sbin/nologin
aemon:x:2:2:daemon:/sbin:/sbin/nologin
dm:x:3:4:adm:/var/adm:/sbin/nologin
p:x:4:7:lp:/var/spool/lpd:/sbin/nologin
...
删除文件每行的第二个字符
[root@rocky dir1]# sed -E 's/(.)./\1/' passwd
rot:x:0:0:root:/root:/bin/bash
bn:x:1:1:bin:/bin:/sbin/nologin
demon:x:2:2:daemon:/sbin:/sbin/nologin
am:x:3:4:adm:/var/adm:/sbin/nologin
...
删除文件每行的最后一个字符
[root@rocky dir1]# sed 's/.$//' passwd
root:x:0:0:root:/root:/bin/bas
bin:x:1:1:bin:/bin:/sbin/nologi
daemon:x:2:2:daemon:/sbin:/sbin/nologi
adm:x:3:4:adm:/var/adm:/sbin/nologi
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologi
删除文件每行的倒数第二个字符
[root@rocky dir1]# sed -E 's/(.).$/\1/' passwd
root:x:0:0:root:/root:/bin/bas
bin:x:1:1:bin:/bin:/sbin/nologi
daemon:x:2:2:daemon:/sbin:/sbin/nologi
adm:x:3:4:adm:/var/adm:/sbin/nologi
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologi
sync:x:5:0:sync:/sbin:/bin/syn
六、Shell变量
变量表示命名的内存空间,将数据存放在内存空间,通过变量名引用,获得数据。
默认情况下定义的变量作用于为该进程,在其他进程中不生效。
# 定义变量
[root@rocky dir1]# aaa=555
[root@rocky dir1]# cat test.sh
#!/bin/bash
echo ${aaa}
# 运行脚本为子进程,其中aaa不生效。
[root@rocky dir1]# bash test.sh
[root@rocky dir1]#
6.1 变量命名
变量命名原则:
- 区分大小写
- 不能用关键字,如 if, for, while 等。
- 只能使用字母,数字,下划线,且不能用数字开头。
变量命名规范:
- 见名知意,使用实际含义的英文单词命名,不使用简写,如ATM
- 变量名大写
- 局部变量小写
- 函数名小写
- 小驼峰,多个单词组成,从第二个单词开始后面每个单词开头大写,如myScore。
- 下划线分割每个单词,如my_score。
6.2 变量类型
6.2.1 环境变量
定义:
- 子进程可以继承父进程的环境变量;
- 子进程修改父进程的环境变量只对子进程和子孙进程生效,不对父进程生效;
- 一般只用于系统配置,不用于shell编程。
用法如下:
# 定义环境变量
[root@rocky dir1]# declare -x aaa=123
[root@rocky dir1]# export bbb=456
# 查看定义的环境变量
env
declare -x
export
[root@rocky dir1]# declare -x
...
declare -x USER="root"
declare -x XDG_DATA_DIRS="/root/.local/share/flatpak/exports/share:/var/lib/flatpak/exports/share:/usr/local/share:/usr/share"
declare -x aaa="123"
declare -x bbb="456"
declare -x which_declare="declare -f"
# 引用变量
[root@rocky dir1]# echo ${aaa}
123
[root@rocky dir1]# echo $bbb
456
# 删除定义
unset aaa
6.2.2 只读变量
只读变量只能读,不能写,用法如下:
# 定义
[root@rocky dir1]# readonly dd
[root@rocky dir1]# declare -r ee
# 查看只读变量
readonly
declare -r
[root@rocky dir1]# declare -r
declare -r dd
declare -r ee
6.2.3 位置变量
定义:在shell脚本中内置的变量,在脚本中通过命令行传递给脚本的参数。
用法如下:
$1,$2,... # 第一个、第二个参数,shift [N]换位置
$0 # 命令本身(执行命令的第一部分)
$* # 所有参数组成的列表
$# # 参数个数
$@ # 所有参数组成的字符串
6.2.4 局部变量
定义:只生效在函数体中的变量,函数外无法使用该变量。
[root@rocky dir1]# cat test.sh
#!/bin/bash
function func() {
local a=123
echo $a
}
func
echo $a
# local定义的局部变量只作用于函数内
[root@rocky dir1]# bash test.sh
123
[root@rocky dir1]#
6.2.5 状态变量
状态变量用符号表示为 $?,表示上一条命令的执行结果。如果上一条语句执行成功则为0,否则为任意一个非0整数。如果上一条语句是个函数,则为函数返回值。
[root@rocky dir1]# ls a
a
[root@rocky dir1]# echo $?
0
[root@rocky dir1]# ls b
ls: cannot access 'b': No such file or directory
[root@rocky dir1]# echo $?
2
当遇到exit退出脚本时,后续的$?取值规则如下:
- 如果exit后面有数字,则取值为这个数字;
- 如果exit后面没有数字,则取值为exit上一条语句的执行结果;
- 如果脚本正常退出,没有exit,则为脚本最后执行语句的执行结果。
七、shell编程典型案例
30鸡和兔的头,80鸡和兔的脚,分别有几只鸡,几只兔。
#!/bin/bash
chicken=0
rabbit=0
for i in {0..30}
do
let legs=2*${i}+4*\(30-${i}\)
if [ $legs -eq 80 ]
then
chicken=$i
rabbit=$[30-${i}]
break
fi
done
echo "There are ${chicken} chickens, ${rabbit} rabbits"
结合编程的for循环,条件测试,条件组合,完成批量创建100个用户,
1)for遍历1..100
2)先id判断是否存在
3)用户存在则说明存在,用户不存在则添加用户并说明已添加。
#!/bin/bash
for((i=1;i<=100;i++))
do
username=user`printf "%03d" $i`
if id $username &> /dev/null; then
echo "user $username is existed"
else
useradd $username
echo "user $username added"
fi
done