Zsh 開發指南(第十四篇 文件讀寫)

導讀

以前咱們也偶爾接觸過讀寫文件的方法,本篇會系統講讀寫文件的各類方法。git

寫文件

寫文件要比讀文件簡單一些,最經常使用的用法是使用 > 直接將命令的輸出重定向到文件。若是文件存在,內容會被覆蓋;若是文件不存在,會被建立。github

% echo abc > test.txt複製代碼

若是不想覆蓋以前的文件內容,能夠追加寫入:shell

% echo abc >> test.txt複製代碼

這樣若是文件存在,內容會被追加寫入進去;若是文件不存在,也會被建立。數組

建立文件

有時咱們只想先建立個文件,等之後須要的時候再寫入。bash

touch 命令用於建立文件(普通文件):微信

% touch test1.txt test2.txt

# 或者用 echo 輸出重定向,效果和 touch 同樣
# 加 -n 是由於不加的話 echo 會輸出一個換行符
% echo -n >>test1.txt >>test2.txt

# 或者使用輸入重定向
% >>test1.txt >>test2.txt </dev/null

# mkdir 用來建立目錄,若是須要在新目錄建立文件
% mkdir dir1 dir2複製代碼

若是文件已經存在,touch 命令會更新它的時間(mtime、ctime、atime 一塊兒更新,其他兩種方法不會)到當前時間。另外下邊的清空文件方法,也均可以用來建立文件。touch 命令的使用比較方便,但若是想盡可能少依賴外部命令,可使用後兩種方法。ide

由於文件建立過程一般不存在性能瓶頸,不用過多考慮性能因素。若是須要建立大量文件,能夠在本身的環境分別用這幾種方法試驗幾回,看須要多少時間。性能

我在樹莓派 3B 簡單測試一下:測試

# 三個腳本,分別建立 1000 個文件
% cat test1 test2 test3
#!/bin/zsh 
touch test1{1..1000}.txt
#!/bin/zsh 
echo -n >>test2{1..1000}.txt
#!/bin/zsh 
>>test3{1..1000}.txt </dev/null複製代碼
# 運行了幾回,結果差很少
% time ./test1; time ./test2; time ./test3
./test1  0.02s user 0.03s system 86% cpu 0.058 total
./test2  0.02s user 0.02s system 70% cpu 0.056 total
./test3  0.03s user 0.01s system 72% cpu 0.055 total複製代碼

另外若是文件數量太多的話,方法2、三要按批次建立,由於一個進程能打開的 fd 總數是有上限的。ui

清空文件

有時咱們須要清空一個現有的文件:

# 使用 echo 輸出重定向
% echo -n >test.txt

# 使用輸入重定向
% >test.txt </dev/null

# 也可使用 truncate 命令清空文件
% truncate -s 0 test.txt複製代碼

一般使用第一種方法便可,比較簡單易懂。非特殊場景儘可能不要用像 truncate 這樣不常見的命令。

刪除文件

刪除文件的方法比較單一,用 rm 命令便可。

% rm test1.txt test2.txt

# -f 參數表明即便文件不存在也不報錯
% rm -f test1.txt test2.txt

# -r 參數能夠遞歸刪除目錄和文件
% rm -r dir1 dir2 test*.txt

# -v 參數表明 rm 會輸出刪除文件的過程
% rm -v test*.txt
removed 'test1.txt'
removed 'test2.txt'複製代碼

刪除文件必須藉助 rm 命令。若是必定要不依賴外部命令的話,zsh/files 模塊裏也有一個 rm 命令,能夠用 zmodload zsh/files 加載,而後 rm 就變成了內部命令,用法基本相同。

% zmodload zsh/files
% which -a rm
rm: shell built-in command
/usr/bin/rm複製代碼

此外 zsh/files 中還有內置的 chgrp、chown、ln、mkdir、mv、rmdir、sync 命令。若是不想依賴外部命令,或者系統環境出問題了用不了外部命令,可使用這些。這能夠做爲命令不存在或者由於命令自己問題執行異常的一個 fallback 方案,來提升腳本的健壯性。

多行文本寫入

一般咱們寫文件時不會每一行都單獨寫入,這樣效率過低。

能夠先把字符串拼接起來,而後一次性寫入,這樣比屢次寫入效率更高:

% str=ab
% str+="\ncd"
% str +="\n$str"

echo $str > test.txt複製代碼

能夠直接把數組寫入到文件,每行一個元素:

% array=(aa bb cc)

% print -l $array > test.txt複製代碼

若是是將一段內容比較固定的字符串寫入到文件,能夠這樣:

# 在腳本中也是如此,第二行之後的行首 > 表明換行,非輸入內容
# <<EOF 表明遇到 EOF 時會終止輸入內容
# 裏邊也可使用變量
% > test.txt <<EOF
> aa
> bb
> cc dd
> ee
> EOF

% cat test.txt
aa
bb
cc dd
ee複製代碼

用 mapfile 讀寫文件

若是不喜歡使用重定向符號,還能夠用哈希表來操做文件。Zsh 有一個 zsh/mapfile 模塊,用起來很方便:

% zmodload zsh/mapfile

# 這樣就能夠建立文件並寫入內容,若是文件存在則會被覆蓋
% mapfile[test.txt]="ab cd"
% cat test.txt
ab cd

# 判斷文件是否存在
% (($+mapfile[test.txt])) && echo good
good

# 讀取文件
% echo $mapfile[test.txt]
ab cd

# 刪除文件
% unset "mapfile[test.txt]"

# 遍歷文件
% for i (${(k)mapfile}) {
> echo $i
> }
test1.txt
test2.txt複製代碼

從文件中間位置寫入

有時咱們須要從一個文件的中間位置(好比從第 100 的字符或者第三行開始)繼續寫入,覆蓋以後的內容。Zsh 並不直接提供這樣的方法,但咱們能夠迂迴實現,先用 truncate 命令把文件截斷,而後追加寫。若是文件後邊的內容還須要保留,能夠在截斷以前先讀取進來(見下文讀文件部分的例子),最後再寫回去。

% echo 1234567890 > test.txt
# 只保留前 5 個字符
% truncate -s 5 test.txt
% cat test.txt
12345 
% echo abcde >> test.txt
% cat test.txt
12345abcde複製代碼

讀文件

讀取整個文件

讀取整個文件比較容易:

% str=$(<test.txt)
% echo $str
aa
bb
cc dd
ee複製代碼

按行遍歷文件

若是文件比較大,那讀取整個文件會消耗不少資源,能夠按行遍歷文件內容:

% while {read i} {
> echo $i
> } <test.txt
aa
bb
cc dd
ee複製代碼

read 命令是從標準輸入讀取一行內容,把標準輸入重定向後,就變成了從文件讀取。

讀取指定行

若是隻須要讀取指定的某行或者某些行,不須要用上邊的方法加本身計數。

# (f)2 是讀取第二行
% echo ${"$(<test.txt)"[(f)2]}
bb複製代碼

讀取文件到數組

讀取文件內容到數組中,每行是數組的一個元素:

% array=(${(f)"$(<test.txt)"})複製代碼

讀取指定數量的字符

有時咱們須要按字節數來讀取文件內容,而不是按行讀取。

% cat test.txt
1234567890
# -k5 是隻最多讀取 5 個字節,-u 0 是從 fd 0 讀取,否則會卡住
% read -k 5 -u 0 str <test.txt
% echo $str
12345複製代碼

向文件中間插入內容

有時咱們會遇到比較麻煩的場景,在某個文件中間插入一些內容,而先後的內容保持不變。

Zsh 並無直接提供這樣的功能,但咱們能夠迂迴實現。

% echo -n 1234567890 > test.txt
# 先所有讀進來
% str=$(<test.txt)
# 截斷文件
% truncate -s 5 test.txt
# 插入內容
% echo -n abcde >> test.txt
# 將後半部分文件追加回去
% echo -n $str[6,-1] >> test.txt
% cat test.txt
12345abcde67890複製代碼

但若是比較比較大的話,就不能將整個文件所有讀進來,能夠先在循環裏用 read -k num 一次讀固定數量的字符,而後寫入一箇中間文件,而後再 truncate 原文件,插入內容。最後再 cat 中間文件 >> 原文件 追加原來的後半部份內容便可。

另外這種從文件中間寫入或者讀取內容的場景,均可以使用 dd 命令實現,能夠自行搜索 dd 命令的用法。

總結

本文比較詳細地介紹了各類讀寫文件的方法,基本能夠覆蓋經常使用的場景。

全系列文章地址:github.com/goreliu/zsh…

付費解決 Windows、Linux、Shell、C、C++、AHK、Python、JavaScript、Lua 等領域相關問題,靈活訂價,歡迎諮詢,微信 ly50247。

相關文章
相關標籤/搜索