Bo2SS

Bo2SS

9 数据提取、软硬连接、线性筛、SED

课程内容#

数据提取操作#

| 命令 | 功能 | 命令 | 功能 |
|:----:|:----|:----:|:----|:----:|:----|:----:|:----|
|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

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,指向一个 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}}

【命令演示】

① 上述常用命令按顺序操作

图片

② 用于替换配置文件的某些配置

  • 图片
  • 删除 👉 添加

  • 删除前做备份

  • 添加时加入标识符 #newadd,方便之后用 sed 操作

  • 直接删除再添加,而不是直接替换,可避免繁琐的模式匹配 [参数值]

随堂练习#

  1. 求字符串中所有数字之和:"1 2 3 4 5 6 7 9 a v 你好 . /8"
  2. 将文件中所有大写字母转换为小写:echo "ABCefg" >> test.log
  3. 找到PATH变量中的最后一个路径
  4. 使用last命令,输出所有的重启信息
  5. /etc/passwd中的内容按照用户名排序
  6. /etc/passwd中的内容按uid排序
  7. 在云主机上查找近 2 个月系统登录用户的总人次
  8. 将云主机中近 2 个月登录的所有用户名,按照次数排序,并输出次数
  9. 将本地的/etc目录下的文件及目录名,每十条保存到一个文件中
  10. /etc/passwd中存放的第 10 到 20 个用户,输出uidgidgroups
  11. 按照用户名查看/etc/passwd中的用户,读到'sync'用户时结束,并输出用户的uidgidgroups
  12. 词频统计

① 使用下面的命令生成一个文本文件 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 替换👉排序👉去重计数👉排序👉显示前几名

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.