文件讀取、權限控制、AWK 文本處理
課程內容#
目錄#
- cd:切換工作目錄
- 參數缺省:回到自己的家,[PS] C 語言不支持缺省參數,可通過宏實現
- 參數~:回到自己的家,可使用 [~ 用戶名] 的方式指定該用戶名的家
- 參數 -:回到上次目錄,適合兩個長路徑的相互切換
- pwd
- -L 邏輯工作目錄
- -P 物理工作目錄【真實】
- 主要體現在軟連接上
- ln -s [要連接的文件] [軟連接的位置 / 或 软连接的位置 / 软连接名]
- 兩者在同一片物理空間,物理目錄一致
- 【刪除】對於軟連接 test 指向一個文件夾
- [rm test] 只刪除這個連接文件
- [rm -r test/] 會刪除連接的文件夾裡的所有內容,危險!
- 雖然該操作會提示 test / 不是一個目錄,但 test / 下已經乾乾淨淨
- 如果連接的是文件不是文件夾,不影響原內容
- [PS] 硬連接不能用在目錄上
- mkdir
- -p 自動創建父目錄,當想創建多級目錄時
- -m 設置權限
- 示例:mkdir -p -m 700 ./test/abc/x
- rmdir:可用 rm 替代
- 絕對路徑:從根目錄 / 開始
- 相對路徑:從當前目錄。或上層目錄.. 開始
文件與目錄的管理#
- ls:顯示文件及目錄信息
- cp:拷貝
- -i 若文件存在,詢問
- -r 遞歸
- -a = -pdr
- p 拷貝時連同文件屬性
- d 拷貝連接文件而不是其指向
- r 遞歸
- -u 源文件比目標文件新才拷貝,適合大容量備份
- -s 拷貝為軟連接;-l 拷貝為硬連接
- cp/mv 多個文件時,最後一個必須是目錄
- ⭐cp 的實現邏輯
- 打開文件 → 讀文件 → 寫文件
- 【如果 cp 的是一個管道】
- 那需要從另一端傳入數據,才能讀取數據再寫
- cp 完後,拷貝結果為存儲管道數據的普通文件
- rm:刪除
- -i 互動模式,會詢問
- -r 遞歸
- -f 強制
- mv:移動
- 本質就是 cp + rm
- -i、-f、-u,類似 cp
- basename:取文件名;dirname:取目錄名
- 不會判斷有沒有文件
- basename /home/xxx/abc → abc
- dirname /home/xxx/abc → /home/xxx
- 一般在 shell 腳本中用
- rename:可以被 cp、mv 取代
文件內容的查閱#
- cat:正向連續讀 [反向:tac]
- -A = -vET
- -v 顯示一般看不到的符號
- -E 顯示斷行符為 $ [同 vim 下 list、 nolist]
- -T 顯示 TAB 為 ^I
- [PS] 如果有 \0...stray 錯誤(拷貝別人代碼時),可以用 - A 看看特殊字符
- -b 列出行號;-n 連同空行列出行號
- -A = -vET
- nl:輸出行號顯示文件
- 選項 [選項參數]👈它倆有順序講究
- -b [a/t] 行號指定的方式 → 對應 [cat -n/cat -b]
- -n [ln/rn/rz] 列出行號的表示方法
- -w [num] 行號所占位數
- 一般用於特殊文本
- more、less、head、tail
- more 和 less 的區別
- more 只能往下翻,搜索沒有高亮
- less 更靈活,可以上下翻,搜索有高亮
- 取 21 - 40 行:man ls | head -n 40 | tail -n -20 【去尾、掐頭,sed 也能實現】
- more 和 less 的區別
- od 以二進制方式查看文件內容,暫時用不到,具體操作見課程速記
修改文件時間與新建文件#
- 三個時間
- mtime [modify]:修改時間【默認顯示】
- ctime [change]:權限修改時間
- atime [access]:訪問時間(記錄成本很高)
- [PS] Mac 下有更多的時間類型,與 Linux 不兼容
- touch 文件
- 主要用來修改時間
- 如果不存在,會自動創建
- 特殊用法用的少,詳見課程速記
- [PS] 可以把文件的時間改回去,不讓人感知
文件隱藏屬性#
可通過 chattr [+/- 選項] 更改
- A:不修改 atime [可提高效率、磁碟壽命]
- S:同步寫入
- 指 IO 同步,避免斷電沒保存 [斷電後內存裡的數據直接消失]
- a:只能增加數據 [日誌]
- 不能修改,不能刪除,即使是 sudo
- 在 vim 下不能修改,但修改 [不用 sudo] 會產生沒有 a 屬性的備份文件
- i:不能刪除、修改、建立連接 [默認為硬連接],相當於【固化】
- s:文件刪除時,直接從磁碟刪除
- 正常情況下,刪除文件,只是把文件與對應磁碟位置的關係解除,內容其實還在磁碟裡,有點像 C 語言的 free ()
- 加了 s 屬性後,刪除文件會將磁碟裡的數據全部置 0,真正的重寫清空
- 這裡一般指機械硬碟,固態硬碟又另說
- 【lsattr】查看文件隱藏屬性
- [PS] 軟連接似乎沒有隱藏屬性
文件的特殊權限#
| 權限 | 權限占位符 | 作用對象 | 效果 |
|:----:|:----:|:----:|:----|:----:|:----|:----:|:----|
|set_uid|s | 二進制程序文件,非腳本 | 執行該程序時獲得程序所有者權限 |
|set_gid|s | 二進制程序文件,目錄 | 在該目錄下,有效組變為目錄所屬組 |
|sticky bit|t | 目錄 | 在該目錄下,用戶只能刪除自己創建的內容 |
可通過 chmod [u/g/ 空 |+/-|s/t] 更改
- set_uid
- ⭐chmod u+s,針對所屬用戶權限
- 占所屬用戶權限的 x 的位置:如果存在 x,則變為 s;不存在,則變為 S
- 舉例:其他用戶通過 passwd 命令修改密碼
- 其他用戶對存放密碼的文件 /etc/shadow 沒有任何權限
- 但 passwd 命令有 s 權限,所以其他有執行權限的用戶在執行時獲得程序所有者權限,從而可以修改密碼文件 /etc/shadow
- set_gid
- ⭐chmod g+s,針對所屬組權限
- 占所屬組權限的 x 的位置:如果存在 x,則變為 s;不存在,則變為 S
- 在這個目錄裡做的事情都是以【目錄所屬組】的身份做的
- 一般作用於目錄
- 而對於二進制程序文件,有點類似 set_uid,但獲得的是【所屬組】的權限
- 方便協同辦公,以組為單位管理目錄下的所有用戶
- sticky bit 黏著位
- ⭐chmod +t,可參考粘滯位—— 維基百科
- 占其他用戶權限的 x 的位置:如果存在 x,則變為 t;不存在,則變為 T
- 舉例:/tmp 目錄及目錄下的一些目錄
命令與文件的查詢#
- which:尋找可執行文件
- 在 PATH 路徑下查找
- 在 zsh 下 ls 是 ls --color=tty 的別名,它會被第二條命令的 ls 誤認為是多個路徑
- 查看 which 的選項,可以通過 which -p ls 對 ls 只做【路徑搜索】
- 學會使用命令替換符
- whereis:尋找更多類型的文件,可指定特定類型
- -b 只查找二進制文件
- -m 只查找 man 手冊中的文件
- -s 只查找源文件
- -u 查找其他文件
- locate:模糊定位
- -i 忽略大小寫
- 基於數據庫,不是實時更新的,可使用 [sudo] updatedb 馬上更新
find:高級查找⭐#
【時間】
- -mtime、-ctime、-atime [單位為天]
- <--__+n___|__n__|__-n__|:
n天之前 [不包含n] | n天前的一天內 | n天內 [包含n]
- 分鐘為單位可查看 man 手冊:-mmin、-cmin、-amin
- <--__+n___|__n__|__-n__|:
- ⭐創建一個文件,文件及當前目錄的 mtime 都會被修改
- 因為每個目錄有一張文件表,裡面記錄文件名和 inode
- 當目錄裡增加了一個文件,該文件表也就多了一個文件名及 inode
- 所以當前目錄的 mtime 也會變
- ❗ 但如果只是修改一個文件,很好理解,當前目錄的 mtime 不會改變
- -newer file 以文件時間作為時間節點
【用戶、用戶組】
- -user 指定 user 名
- 查找用戶 hz 在 10 分鐘內活躍的進程 ID 【PID】
- 進程文件在 /proc 下,都是虛擬的,文件 [目錄] 大小為 0
- 應用:殺死進程
- [PS] 進程 ID 和 inode 不是一回事,不能殺 inode
- -uid、-gid、-group、nouser、nogroup 的使用同 - user
【文件、文件權限】
- -name 匹配文件名
- (... -o ...) 邏輯或,注意括號用 \ 轉義,兩端裡面有空格
- xargs—— 參數代換,不需要再移到前面用命令替換符
- -size [+ 大於 - 小於]
- 可以查找空文件,用來做清理,但要注意一些特殊文件 [.py 等]
- -type
- 7 種文件類型:f b c d l s p
- -perm 775/-775
- 後者包含前者,即 - 775 包括 775、776、777
- -exec find 自帶的執行工具
- 統計已編寫的 c、cpp、sh 代碼行數
- -exec— 命令的開始
- {} —— find 的結果
- ; —— 命令的結束
➕AWK 文本數據處理#
awk [-Ffv] 'BEGIN { commands } pattern { commands } END { commands } file'
-
常用選項
- -F fs:指定分隔符 fs,可以是字符或正則表達式,默認為空格
- -v var=value:傳遞外部變量 var 給 awk
- -f scriptfile:從腳本文件 scriptfile 讀取 awk 命令
-
BEGIN {}:開始執行一次
-
pattern {}:重點⭐
- awk 讀取的每一行都會執行一次
- 如果沒有提供 pattern 語句塊,則默認執行 {print}
-
END {}:最後執行一次
-
[PS]
- 可以從文件 file 讀取數據,也可以用管道 "|" 傳遞數據
- commands 支持各種語言的 print 函數,如 C 語言的 printf ()
-
示例:統計最近登錄的總時長
- 先預處理數據
- 使用 awk 取到需要的時長數據
- 使用 awk 做計算
- 常用內建變量:$n、NF、NR
-
[PS]
- 參考文檔 ——AWK 程序設計語言
- 不用強背,知道它的功能即可
- 其偏向於專業性;其實是一門語言,有自己的語法結構
- 有很多變種
附加知識點#
- 對於 /var 下的 run 目錄:ls -al run/,ls -ald run/,ls -ald run
- 三者的結果都不一樣,ls -ald run 也可以用 ls -al run
- 注意斜杠 / 的存在
- PATH 變量是在進程裡,斷開 SSH 後重連,PATH 變量會恢復原樣
- 嚴格說是在內存裡
- 管道文件 [mkfifo 創建的] 和管道 [命令中的 | ] 的區別
- 本質上沒有區別:一進一出,沒輸入就會產生阻塞
- 但是,| 隱含創建了一個進程,處理了數據後再返回給原進程
- ⭐Linux 中,文本處理的基本單位:行
- cat、tac、scanf、printf
- 【硬連接】
- 相當於一個文件多了一個別名,刪除一個別名不影響文件
- 對於存在硬連接的 a、b 文件
- 通過 ls -i 查看 inode [文件結點號]
- 會發現 a、b 兩個文件的 inode 相同,且文件連接數為 2
- chmod -R ...:遞歸,修改目錄及下面所有文件的權限
- 解壓壓縮:gzip/gunzip、tar -c 壓縮 /-x 解壓 /-v 顯示冗餘信息 /-z 通過 gzip 操作
- tar 不能解壓.gz 文件,使用 gunzip 即可
- ⭐創建的目錄默認大小為 4096 Byte = 4K
- 對應磁碟的一個 block,存儲的是一個文件表
- ❗目錄大小不會為 0,/proc 下的大小為 0 的目錄,屬於虛擬文件系統,不是真的目錄
思考點#
- C 的源文件被編譯後的 a.out,使用./a.out 執行,這裡的./ 是什麼意思
- 沒有特殊含義,就是【當前路徑】,用的是相對路徑執行
- 也可以使用絕對路徑執行
- ❓直接 a.out 呢?
- a.out 會被認為是命令,從而報錯 command not found
- 對於默認的字符,系統默認為是執行命令,會找內置命令或去 PATH 路徑下找
- 默認為命令而不是文件,因為命令更常用
- 輸出重定向的細節
- 方式①:會排隊,按順序輸出
- 方式②:同時傳,數據會亂序
- &1 = 1 號文件
- 此外,方式①還有順序要求
- 這樣,2 號文件沒有輸出到 1 號文件裡
- 這裡順序有講究,得先打開 xxx.log 文件!
- find 找不到文件時,再 ls 容易讓人產生錯覺
- 相當於 ls 空,即 ls 當前目錄
Tips#
- 【避免 rm 危險操作】
- 寫腳本定時 [contab] 將代碼上傳到 Github、碼雲
- 把 rm 封裝改成 mv,給自己定義的回收站,寫腳本定時清理超過 3 天的文件
- 【小技巧】shell 下,輸入一小部分代碼,按上下鍵可以匹配曾輸過的匹配的代碼
- [其它] 使用驚嘆號!開頭
- !mk 直接輸入在歷史記錄裡最近的匹配命令
- !9812 直接輸入 history 裡第 9812 行
- [其它] 使用驚嘆號!開頭
- 一般 - r、-R 表示遞歸,可自己嘗試,小寫被佔用了就會用大寫
- 聊到 link 默認指硬連接
- man 手冊搜索參數時,使用 "/-z,",在後面加一個逗號,匹配數更少
- $() 可以充當命令替換符 ``