课程内容#
数据提取操作#
| 命令 | 功能 | 命令 | 功能 |
|:----:|:----|:----:|:----|:----:|:----|:----:|:----|
|cut | 切分 | grep | 检索 |
|sort | 排序 | wc | 统计字符、字数、行数 |
|uniq | 去重 | tee | 双向重定向 |
|split | 文件切分 | xargs | 参数代换 |
|tr | 替换、压缩、删除 | | |
cut#
—— 菜刀
- -d c 以字符 c 分割
- 可用 "" 或 '' 包围 c,很灵活
- 默认为空格
- -f [n/n-/n-m/-m] 选择第 n 块 / 第 n-end 块 / 第 n-m 块 / 第 1-m 块
- -b [n-/n-m/-m] 字节
- -c [n-/n-m/-m] 字符
grep#
常见操作见:tldr grep
- -c 统计搜寻到的次数 [文件为单位]
- -n 顺序输出所在行号
- -v 输出不匹配的 [补集]
- -C 3 输出附近 3 行的内容
- -i 大小写敏感
- [PS] -n、-c 冲突,优先显示 - c 结果
- 示例
- 统计路径下包含 doubleliu3 的行数
- 使用 cut+awk 或直接使用 awk
- 查看 hz 相关正在运行的进程
- ps -ef:类似 Windows 下的任务管理器
- 相比,ps -aux 显示的信息更多,在早期偏向 UNIX 系统
- [PS] ps -ef 中,PPID 是父进程的 ID
- 统计路径下包含 doubleliu3 的行数
sort#
类似 Excel 的排序功能,默认根据行首按 ASCII 码排序
- -t 分隔符,默认为 TAB
- -k 以哪个区间排序
- -n 纯数字排序
- -r 反向排序
- -u uniq [但不方便计数]
- -f 忽略大小写 [默认];-V [不忽略大小写]
【示例】将用户信息根据 uid 按纯数字排序
cat /etc/passwd | sort -t : -k 3 -n
【经测试】
- 排序时默认
- 省略了特殊符号,如下划线 "_"、"*"、"/" 等
- 还忽略大小写,排好序后把小写放在大写前面 [-V 可以不忽略大小写]
wc#
- -l 行数
- -w 字数
- -m 字符数;-c 字节数
【示例】
① 最近登录系统的总次数
last | grep -v "^$" | grep -v "begins" | wc -l
② PATH 路径的相关统计:字符数、单词数、变量数、取最后一个变量
uniq#
连续的重复的才算重复,一般与 sort 配合
- -i 忽略大小写
- -c 计数
【示例】统计最近用户的登录次数,根据次数从大到小排序
tee#
既显示在终端,又写进文件
- 默认覆盖原文件
- -a 追加不覆盖
【示例】
split#
切分一个文件,适合处理大文件
- -l num 按 num 行切分
- -b size 按 size 大小切分,512 [默认 byte]、512k、512m
- 可能存在首行、末行不完整,所以可用下面方式👇
- ❗ -C size 按最多 size 大小切分,并保证不破坏行数据!
- -n num 按大小平分成 num 份
【示例】将 /etc 下的文件列表每 20 行切分出一个文件
xargs#
参数代换,适合不接收标准输入的命令,等价于用命令替换符的方式
- -exxx 读到 "xxx" 结束
- -p 执行整个指令前询问
- -n num 指定每次接收的参数个数⭐,而不是一次性全部传入
- 适合只能读一个参数的命令 [如 id] 或相关场景
tr#
对标准输入的字符替换、压缩、删除,可查看 tldr tr
tr [选项] < 字符 / 字符集 1> < 字符 / 字符集 2>
- 默认替换字符集 1👉字符集 2,一一对应
- 字符集 1 较字符集 2 多出的字符,以字符集 2 最后一个字符作为替换
- -c 替换所有不属于字符集 1 的字符👉字符 2
- -s 压缩,将连续重复的字符 1👉一个字符 1 【❗与 - c 搭配时看字符 2】
- -d 删除所有属于字符集 1 的字符
- -t 先删除字符集 1 中较字符集 2 多出的字符,再一一对应替换【❗ 注意与默认方式的区别】
【示例】
①简单使用
- -s 也需要参数,与 - c 搭配时默认用字符 2
- -t 只管一一对应了的字符,字符集 1 比字符集 2 多出的字符不管
②词频统计
- tr 替换👉排序👉去重计数👉排序👉显示前几名
软、硬连接#
硬连接可以减少存储使用,软连接多了一个 inode 和 block
【背景介绍】
- ext4 文件系统 —— 三个组成部分 ——inode、block、superblock
- inode:文件结点
- 一个 inode 对应一个文件
- 存储文件信息 [文件权限、所属者、时间...] 和文件真实位置 [blocks 位置]
- 如果存不下 blocks 位置,会用多级 blocks
- block:文件真实存放位置,一个 block 一般是 4096 bytes
- superblock:至少两个,存储文件系统的整体信息 [如 inode、block...]
【硬连接】相当于一个别名
- 与原文件拥有相同的 inode
- 文件的连接数 > 1
- [PS]
- 删除别名不影响原文件
- 当前目录和父目录都是硬连接 [特殊的目录]
- 但是硬连接不支持目录,可能存在死循环等问题,参考:
- Why are hard links to directories not allowed in UNIX/Linux?——StackExchange
- Why are hard links not allowed for directories?——StackExchange
- linux 为什么不能硬链接目录?—— 知乎
【软连接】相当于一个快捷方式
- 创建了一个新的文件,拥有自己的 inode,指向一个 block [存储文件的真实位置]
- 文件类型为 link
- [PS] 比硬连接更常用
线性筛#
-
shell 中的数组没必要初始化,一开始就为空
- 其实不管什么变量,一开始都是空,没有类型
-
学会【变量 x == x】的判空操作
-
数组的下标可以直接使用变量名,可以不用 ${} 包裹
【与素数筛的效果比较】
求 2~20000 的素数和
-
在 shell 中,效果还没有素数筛好,可能原因是:
- shell 涉及很多系统的调用,不能纯看数学层面了
- 执行 shell 脚本会把 CPU 跑满,与 C 语言中的效果不具有可比性
- 取余操作
➕SED 脚本编辑#
主要用于编辑脚本,语法可借鉴 vim
【常用操作】替换 [批量、按行、匹配]、删除
# 替换每行匹配的第一个字符串模式 [支持正则表达式]
sed 's/{{regex}}/{{replace}}/' {{filename}}
# 替换匹配的行的第一个字符串、删除匹配的行
sed '/{{line_pattern}}/s/{{regex}}/{{replace}}/' {{filename}}
sed '/{{line_pattern}}/d' {{filename}}
# 可以使用其它分割符,比如'#',应对需要用到'/'字符的场景
sed 's#{{regex}}#{{replace}}#' {{filename}}
# 删除两个匹配模式之间的所有行
sed '/{{regex}}/,/{{regex}}/d' {{filename}}
# [特殊]删除匹配行之后/之前的内容
sed '/{{regex}}/,$d' {{filename}}
sed '/{{regex}}/,$!d' {{filename}}
- sed -i 将修改写入文件
- sed '.../g' 末尾添加 g 可全局操作
- sed '.../d' 末尾为 d 为删除操作
- sed '/.../,/...' 逗号可用来匹配两个模式 [匹配一个段落]
- 参考使用 sed 删除两个匹配模式之间的所有行?—— 腾讯云社区
【命令演示】
① 上述常用命令按顺序操作
② 用于替换配置文件的某些配置
-
删除 👉 添加
-
删除前做备份
-
添加时加入标识符 #newadd,方便之后用 sed 操作
-
直接删除再添加,而不是直接替换,可避免繁琐的模式匹配 [参数值]
随堂练习#
- 求字符串中所有数字之和:"1 2 3 4 5 6 7 9 a v 你好 . /8"
- 将文件中所有大写字母转换为小写:echo "ABCefg" >> test.log
- 找到
PATH
变量中的最后一个路径 - 使用
last
命令,输出所有的重启信息 - 将
/etc/passwd
中的内容按照用户名排序 - 将
/etc/passwd
中的内容按uid
排序 - 在云主机上查找近 2 个月系统登录用户的总人次
- 将云主机中近 2 个月登录的所有用户名,按照次数排序,并输出次数
- 将本地的
/etc
目录下的文件及目录名,每十条保存到一个文件中 - 将
/etc/passwd
中存放的第 10 到 20 个用户,输出uid
、gid
和groups
- 按照用户名查看
/etc/passwd
中的用户,读到'sync'
用户时结束,并输出用户的uid
、gid
和groups
- 词频统计
① 使用下面的命令生成一个文本文件 test.txt
cat >> test.txt << xxx
nihao hello hello 你好
nihao
hello
ls
cd
world
pwd
xxx
② 统计 a.txt 中各词的词频,并按照从大到小的顺序输出。
答案
【1】
[巧妙解法,需在bash下]
echo "1 2 3 4 5 6 7 9 a v 你好 . /8" | tr -s -c 0-9 "\n" | echo $[`tr "\n" "+"`0]
[for循环]
sum=0
for i in `echo "1 2 3 4 5 6 7 9 a v 你好 . /8" | tr -s -c 0-9 "\n"`; do
for> sum=$[$sum+$i]
for> done
[awk解法1]
echo "1 2 3 4 5 6 7 9 a v 你好 . /8" | tr -s -c 0-9 "\n" | awk -v sum=0 '{sum += $1} END { print sum }'
[awk解法2]
echo "1 2 3 4 5 6 7 9 a v 你好 . /8" | tr -s -c 0-9 " " | awk -v sum=0 '{for (i = 1; i <= NF; i++) {sum += $i} } END{print sum}'
【2】 cat test.log | tr A-Z a-z > test.log
【3】 echo ${PATH} | tr ":" "\n" | tail -1
【4】 last | grep "reboot"
【5】 cat /etc/passwd | sort
【6】 cat /etc/passwd | sort -t : -k 3 -n
【7】 last -f /var/log/wtmp.1 -f /var/log/wtmp | grep -v "^$" | grep -v "begins" | grep -v "reboot" | grep -v "shutdown" | wc -l
【8】 last -f /var/log/wtmp.1 -f /var/log/wtmp | grep -v "^$" | grep -v "begins" | grep -v "reboot" | grep -v "shutdown" | cut -d " " -f 1 | sort | uniq -c | sort -n -r
【9】 ls /etc | split -l 10
【10】 cat /etc/passwd | head -20 | tail -10 | cut -d : -f 1 | xargs -n 1 id
【11】 cat /etc/passwd | cut -d : -f 1 | xargs -e"sync" -n 1 id
【12】
cat test.txt | tr -s " " "\n" | sort | uniq -c | sort -n -r
[如果想让词在前、次数在后,使用awk颠倒]
cat test.txt | tr -s " " "\n" | sort | uniq -c | sort -n -r | awk '{print $2, $1}'
Tips#
- 面试常考:词频统计
- tr 替换👉排序👉去重计数👉排序👉显示前几名