day020-sed和find
文章目录
- 1. sed
- 1.1 查找、过滤文本
- 1.1.1 根据行号取行
- 1.1.2 根据行号取范围
- 1.1.3 过滤出指定行
- 1.1.4 过滤出指定范围内容
- 1.2 替换文件内容
- 1.2.1 将文件中虚拟用户命令解释器替换成/bin/bash
- 1.2.2 修改原文件并备份
- 1.2.3 为每行开头加上#
- 1.3 反向引用(后向引用)
- 1.3.1 将用户名和命令解释器调换位置
- 1.3.2 将日志中时间格式改为年月日
- 1.4 删除
- 1.4.1 按照行号删除
- 1.4.2 将空行或以#开头的行删除
- 1.5 增加数据
- 1.5.1 a
- 1.5.2 i
- 1.5.3 c
- 1.6 案例:排除/删除sshd配置文件中的空行或注释行(不需要真的删除)
- 2. find
- 2.1 find基础使用
- 2.1.1 找出/etc下以.conf结尾的文件
- 2.1.2 找出/etc下大于100k的文件
- 2.1.3 找出/var/log目录下以.log结尾7天前的文件
- 2.2 find进阶使用
- 2.2.1 在/etc下找出以.conf结尾的文件,找出这些文件中包含root或oldboy的行
- 2.2.2 在/etc下找出以.conf结尾的文件,将这些文件打包
- 2.2.3 找出/var/log目录下以.log结尾的文件复制到/backup/logs目录
- 3. 踩坑记录
- 3.1 find: 遗漏“-exec”的参数
- 4. 思维导图
1. sed
sed格式:
sed 选项 脚本 文件
sed
(Stream Editor)是 Linux/Unix 下的流式文本编辑器,用于对文本进行查找、替换、删除、插入等操作,支持正则表达式。sed
的 “流式编辑”(Stream Editing)特性体现在它处理文本的方式上:逐行读取、即时处理、无需加载整个文件到内存。grep
和awk
在处理文本时,默认也是逐行读取数据(流式处理)
1.1 查找、过滤文本
- sed默认是自动打印模式,从输入(stdin或文件)逐行读取数据,并输出原文件数据。
- -n:取消自动打印模式
1.1.1 根据行号取行
- 脚本选项p:print,将结果输出
[root@oldboy99-Kylin ~/oldboy]# sed -n '1p' passwd
root:x:0:0:root:/root:/bin/bash
1.1.2 根据行号取范围
[root@oldboy99-Kylin ~/oldboy]# sed -n '1,5p' 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
1.1.3 过滤出指定行
- -r:使用扩展正则表达式
- 过滤出包含root或oldboy的行
[root@oldboy99-Kylin ~/oldboy]# sed -rn '/root|oldboy/p' passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
oldboy:x:1000:1000::/home/oldboy:/bin/bash
1.1.4 过滤出指定范围内容
- 按时间范围过滤出日志内容
[root@oldboy99-Kylin ~/oldboy]# sed -n '/11:05:00/,/11:06:00/p' access.log |head -n 1
114.84.238.226 - - [22/Nov/2015:11:05:00 +0800] "GET /online/oldboyonline/order/mapInfoWindow.css HTTP/1.1" 200 608 "http://www.papaonline.com.cn/online/oldboyonline/order/orderNow.jsp" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.152 Safari/537.36"
[root@oldboy99-Kylin ~/oldboy]# sed -n '/11:05:00/,/11:06:00/p' access.log |wc -l
3366
- 取出日志中从第一行到11:30范围的日志,并取出第一列,统计最多的ip,取前五名
[root@oldboy99-Kylin ~/oldboy]# sed -n '1,/11:30:00/p' access.log |awk '{print $1}' |sort |uniq -c |sort -k1nr |head -55883 112.64.171.985574 58.220.223.62957 116.216.0.60799 114.83.184.139792 121.235.250.231
# 用awk过滤
[root@oldboy99-Kylin ~/oldboy]# awk 'NR==1,/11:30:00/{print $1}' access.log |sort |uniq -c |sort -k1nr |head -55883 112.64.171.985574 58.220.223.62957 116.216.0.60799 114.83.184.139792 121.235.250.231
1.2 替换文件内容
- 脚本选择:s###g
- s:substitute,替换
- g:global,整行替换
- 中间的分隔符可以换成其他的符号:@、/等
1.2.1 将文件中虚拟用户命令解释器替换成/bin/bash
- 基础替换不会改变文件内容
- 替换操作时需要查看输出结果,所以不要加-n;也不需要指定输出,不要加p
[root@oldboy99-Kylin ~/oldboy]# sed 's#/sbin/nologin#/bin/bash/#g' passwd |head -5
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/bin/bash/
daemon:x:2:2:daemon:/sbin:/bin/bash/
adm:x:3:4:adm:/var/adm:/bin/bash/
lp:x:4:7:lp:/var/spool/lpd:/bin/bash/
- -i:in-place,直接修改文件内容
[root@oldboy99-Kylin ~/oldboy]# sed -i 's#/sbin/nologin#/bin/bash/#g' passwd
[root@oldboy99-Kylin ~/oldboy]# head -n 5 passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/bin/bash/
daemon:x:2:2:daemon:/sbin:/bin/bash/
adm:x:3:4:adm:/var/adm:/bin/bash/
lp:x:4:7:lp:/var/spool/lpd:/bin/bash/
[root@oldboy99-Kylin ~/oldboy]# grep '/sbin/nologin' passwd
[root@oldboy99-Kylin ~/oldboy]#
1.2.2 修改原文件并备份
- -i[扩展名]:直接修改文件(如果指定扩展名则备份文件)
[root@oldboy99-Kylin ~/oldboy]# ll
-rw-r--r-- 1 root root 2006 5月 26 14:33 passwd
[root@oldboy99-Kylin ~/oldboy]# sed -i.bak 's#/sbin/nologin#/bin/bash#g' passwd
[root@oldboy99-Kylin ~/oldboy]# ll
-rw-r--r-- 1 root root 1874 5月 26 14:34 passwd
-rw-r--r-- 1 root root 2006 5月 26 14:33 passwd.bak
[root@oldboy99-Kylin ~/oldboy]# grep '/sbin/nologin' passwd
[root@oldboy99-Kylin ~/oldboy]#
1.2.3 为每行开头加上#
[root@oldboy99-Kylin ~/oldboy]# sed 's@^@#@g' passwd
#root:x:0:0:root:/root:/bin/bash
#bin:x:1:1:bin:/bin:/bin/bash
#daemon:x:2:2:daemon:/sbin:/bin/bash
#adm:x:3:4:adm:/var/adm:/bin/bash
……
1.3 反向引用(后向引用)
- 通过正则表达式把要处理的内容进行分组,在后面通过数字引用进行处理
1.3.1 将用户名和命令解释器调换位置
[root@oldboy99-Kylin ~/oldboy]# sed -r 's#^(.+)(:x:.+:)(/.+)$#\3\2\1#g' passwd |head -5
/bin/bash:x:0:0:root:/root:root
/sbin/nologin:x:1:1:bin:/bin:bin
/sbin/nologin:x:2:2:daemon:/sbin:daemon
/sbin/nologin:x:3:4:adm:/var/adm:adm
/sbin/nologin:x:4:7:lp:/var/spool/lpd:lp
1.3.2 将日志中时间格式改为年月日
- 过滤[]时要加反斜线
[root@oldboy99-Kylin ~/oldboy]# head -1 access.log
101.226.61.184 - - [22/Nov/2015:11:02:00 +0800] "GET /mobile/sea-modules/gallery/zepto/1.1.3/zepto.js HTTP/1.1" 200 24662 "http://m.oldboyedu.com.cn/mobile/theme/oldboy/home/index.html" "Mozilla/5.0 (Linux; U; Android 5.1.1; zh-cn; HUAWEI CRR-UL00 Build/HUAWEICRR-UL00) AppleWebKit/533.1 (KHTML, like Gecko)Version/4.0 MQQBrowser/5.4 TBS/025478 Mobile Safari/533.1 MicroMessenger/6.3.7.51_rbb7fa12.660 NetType/3gnet Language/zh_CN"
[root@oldboy99-Kylin ~/oldboy]# sed -r 's#^(.+\[)([0-9]+)/([A-Z][a-z]+/)(2015)(:.+)$#\1\4/\3\2\5#g' access.log |head -1
101.226.61.184 - - [2015/Nov/22:11:02:00 +0800] "GET /mobile/sea-modules/gallery/zepto/1.1.3/zepto.js HTTP/1.1" 200 24662 "http://m.oldboyedu.com.cn/mobile/theme/oldboy/home/index.html" "Mozilla/5.0 (Linux; U; Android 5.1.1; zh-cn; HUAWEI CRR-UL00 Build/HUAWEICRR-UL00) AppleWebKit/533.1 (KHTML, like Gecko)Version/4.0 MQQBrowser/5.4 TBS/025478 Mobile Safari/533.1 MicroMessenger/6.3.7.51_rbb7fa12.660 NetType/3gnet Language/zh_CN"
1.4 删除
1.4.1 按照行号删除
- 脚本参数d:删除
- 不会影响原文件
[root@oldboy99-Kylin ~/oldboy]# sed '1d' passwd
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
……
# 按照行号范围删除
[root@oldboy99-Kylin ~/oldboy]# sed '1,5d' passwd
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
……
1.4.2 将空行或以#开头的行删除
[root@oldboy99-Kylin ~/oldboy]# sed -r '/^$|^#/d' 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
……
1.5 增加数据
脚本参数 | 说明 |
---|---|
a | append,在指定的行后面追加一行 |
i | insert,在指定的行上面追加一行 |
c | replace,把指定的行内容替换掉 |
1.5.1 a
[root@oldboy99-Kylin ~/oldboy]# sed '1a 孙克旭' passwd
root:x:0:0:root:/root:/bin/bash
孙克旭
bin:x:1:1:bin:/bin:/sbin/nologin
……
1.5.2 i
[root@oldboy99-Kylin ~/oldboy]# sed '1i 孙克旭' passwd
孙克旭
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
……
1.5.3 c
[root@oldboy99-Kylin ~/oldboy]# sed '1c 孙克旭' passwd
孙克旭
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
……
1.6 案例:排除/删除sshd配置文件中的空行或注释行(不需要真的删除)
- grep:
[root@oldboy99-Kylin ~]# grep -Ev '^$|^#' /etc/ssh/sshd_config
Port 12345
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
……
- sed:
- !:取反,注意符号的位置
[root@oldboy99-Kylin ~]# sed -rn '/^$|^#/!p' /etc/ssh/sshd_config
Port 12345
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
……
############################################
[root@oldboy99-Kylin ~]# sed -r '/^$|^#/d' /etc/ssh/sshd_config
Port 12345
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
……
- awk:
[root@oldboy99-Kylin ~]# awk '!/^$|^#/' /etc/ssh/sshd_config
Port 12345
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
……
2. find
- 根据指定的目录查找内容(文件、目录)
选项 | 说明 |
---|---|
-type | f:文件 d:目录 |
-name | 文件名 |
-size | 文件大小,单位k(小写)、M(大写)、G(大写) |
-mtime | 文件创建时间,+7:7天以前 |
2.1 find基础使用
2.1.1 找出/etc下以.conf结尾的文件
[root@oldboy99-Kylin ~]# find /etc/ -type f -name '*.conf'
/etc/resolv.conf
/etc/dnf/protected.d/systemd.conf
/etc/dnf/protected.d/sudo.conf
/etc/dnf/protected.d/dnf.conf
……
2.1.2 找出/etc下大于100k的文件
[root@oldboy99-Kylin ~]# find /etc/ -type f -size +100k
/etc/pki/ca-trust/extracted/edk2/cacerts.bin
/etc/pki/ca-trust/extracted/java/cacerts
……
2.1.3 找出/var/log目录下以.log结尾7天前的文件
[root@oldboy99-Kylin ~]# find /var/log/ -type f -name '*.log' -mtime +7
/var/log/dracut.log
/var/log/.kylin-post-actions-nochroot.log
/var/log/anaconda/anaconda.log
……
2.2 find进阶使用
2.2.1 在/etc下找出以.conf结尾的文件,找出这些文件中包含root或oldboy的行
- 是文件内容中包含……,不是文件名
- 管道的作用是将左侧的命令结果作为右侧的命令输入
- 这里需要将文件路径作为grep的参数,而不是数据输入,所以使用xargs将左侧结果按行转换成右侧命令的参数
grep
的颜色输出在通过管道或xargs
时会默认被禁用。
[root@oldboy99-Kylin ~]# find /etc/ -type f -name '*.conf' |xargs grep -E 'root|oldboy' --color=auto
/etc/libreport/events.d/bugzilla_anaconda_event.conf: sed 's/^.*rootpw.*$/<auto-removed line containing rootpw>/' -i $sf
/etc/libreport/events.d/collect_dnf.conf: if [[ $username != "root" ]]; then
/etc/libreport/events.d/abrt_event.conf:# Example: if you want all users (not just root) to be able to see some problems:
/etc/libreport/events.d/smart_event.conf:# Access to /dev/sda usually requires root.
……
[root@oldboy99-Kylin ~]# grep -E 'root|oldboy' `find /etc/ -type f -name '*.conf'`
/etc/libreport/events.d/bugzilla_anaconda_event.conf: sed 's/^.*rootpw.*$/<auto-removed line containing rootpw>/' -i $sf
/etc/libreport/events.d/collect_dnf.conf: if [[ $username != "root" ]]; then
/etc/libreport/events.d/abrt_event.conf:# Example: if you want all users (not just root) to be able to see some problems:
/etc/libreport/events.d/smart_event.conf:# Access to /dev/sda usually requires root.
……
[root@oldboy99-Kylin ~]# find /etc/ -type f -name '*.conf' -exec grep -E --color=auto 'root|oldboy' {} \; sed 's/^.*rootpw.*$/<auto-removed line containing rootpw>/' -i $sfif [[ $username != "root" ]]; then
# Example: if you want all users (not just root) to be able to see some problems:
# Access to /dev/sda usually requires root.
# Therefore we run it as post-create event, thus: under root.# Can't do it as analyzer step, non-root can't read log.
rootpw
……
- -exec的方式显示的结果不明显
2.2.2 在/etc下找出以.conf结尾的文件,将这些文件打包
[root@oldboy99-Kylin ~]# find /etc/ -type f -name '*.conf' |xargs tar zcf /backup/etc-conf.tar.gz
tar: 从成员名中删除开头的“/”
tar: 从硬连接目标中删除开头的“/”
[root@oldboy99-Kylin ~]# tar zcf /backup/etc-conf.tar.gz `find /etc/ -type f -name '*.conf'`
tar: 从成员名中删除开头的“/”
tar: 从硬连接目标中删除开头的“/”
# 错误方法:
[root@oldboy99-Kylin ~]# find /etc/ -type f -name '*.conf' -exec tar zcf /backup/etc-conf.tar.gz {} \;
tar: 从成员名中删除开头的“/”
tar: 从成员名中删除开头的“/”
tar: 从成员名中删除开头的“/”
……
[root@oldboy99-Kylin /backup]# tar tf etc-conf.tar.gz
etc/pulse/daemon.conf
- find的结果会进入{}内;
- 如果有10个文件,tar命令执行了10次,而且每次都会覆盖原压缩包,所以最后的压缩包只有一个文件
[root@oldboy99-Kylin ~]# find /etc/ -type f -name '*.conf' -exec tar zcf /backup/etc-conf.tar.gz {} +
tar: 从成员名中删除开头的“/”
tar: 从硬连接目标中删除开头的“/”
- +:批量处理模式:
会让find
将匹配到的所有文件一次性传递给后面的命令
2.2.3 找出/var/log目录下以.log结尾的文件复制到/backup/logs目录
- 问题和上面的tar一样,是参数位置问题
- -t:后面指定目标目录;将源文件复制到该目录中
[root@oldboy99-Kylin ~]# find /var/log/ -type f -name '*.log' |xargs cp -t /backup/logs/
cp: 不会以'/var/log/dnf.librepo.log' 覆盖刚创建的'/backup/logs/dnf.librepo.log'
cp: 不会以'/var/log/hawkey.log' 覆盖刚创建的'/backup/logs/hawkey.log'
[root@oldboy99-Kylin ~]# yes |cp `find /var/log/ -type f -name '*.log'` /backup/logs/
cp:是否覆盖'/backup/logs/sssd_implicit_files.log'?
cp:是否覆盖'/backup/logs/sssd.log'?
cp:是否覆盖'/backup/logs/sssd_nss.log'?
- yes:自动对所有的询问回答yes
- 或者不使用别名cp:\cp
find /var/log/ -type f -name '*.log' -exec cp {} /backup/logs/ \;
3. 踩坑记录
3.1 find: 遗漏“-exec”的参数
[root@oldboy99-Kylin ~]# find /var/log/ -type f -name '*.log' -exec cp {} /backup/logs/ +
find: 遗漏“-exec”的参数
-exec
的+
参数必须直接放在{}
后面
4. 思维导图
【金山文档】 思维导图 https://www.kdocs.cn/l/co3I7PtpTYQX