### 导读 之前我们也偶尔接触过读写文件的方法,本篇会系统讲读写文件的各种方法。 ### 写文件 写文件要比读文件简单一些,最常用的用法是使用 > 直接将命令的输出重定向到文件。如果文件存在,内容会被覆盖;如果文件不存在,会被创建。 ``` % echo abc > test.txt ``` 如果不想覆盖之前的文件内容,可以追加写入: ``` % echo abc >> test.txt ``` 这样如果文件存在,内容会被追加写入进去;如果文件不存在,也会被创建。 #### 创建文件 有时我们只想先创建个文件,等以后需要的时候再写入。 touch 命令用于创建文件(普通文件): ``` % touch test1.txt test2.txt # 或者用 echo 输出重定向,效果和 touch 一样 # 加 -n 是因为不加的话 echo 会输出一个换行符 % echo -n >>test1.txt >>test2.txt # 或者使用输入重定向 % >>test1.txt >>test2.txt >test2{1..1000}.txt #!/bin/zsh >>test3{1..1000}.txt test.txt # 使用输入重定向 % >test.txt test.txt ``` 可以直接把数组写入到文件,每行一个元素: ``` % array=(aa bb cc) % print -l $array > test.txt ``` 如果是将一段内容比较固定的字符串写入到文件,可以这样: ``` # 在脚本中也是如此,第二行以后的行首 > 代表换行,非输入内容 # < test.txt < 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=$( echo $i > } test.txt # 先全部读进来 % str=$(> test.txt # 将后半部分文件追加回去 % echo -n $str[6,-1] >> test.txt % cat test.txt 12345abcde67890 ``` 但如果比较比较大的话,就不能将整个文件全部读进来,可以先在循环里用 read -k num 一次读固定数量的字符,然后写入一个中间文件,然后再 truncate 原文件,插入内容。最后再 cat 中间文件 >> 原文件 追加原来的后半部分内容即可。 另外这种从文件中间写入或者读取内容的场景,都可以使用 dd 命令实现,可以自行搜索 dd 命令的用法。 ### 总结 本文比较详细地介绍了各种读写文件的方法,基本可以覆盖常用的场景。