課程內容#
數據提取操作#
| 命令 | 功能 | 命令 | 功能 |
|:----:|:----|:----:|:----|:----:|:----|:----:|:----|
|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 替換👉排序👉去重計數👉排序👉顯示前幾名