我有一个脚本处理来自慢速大容量存储器的许多小文件.
出于性能原因,我将文件读取到变量,然后使用此变量进行所有处理.这允许我只读取一次文件.
这很有效,除非最后一行为空,那么变量将比文件短一行,请参见下面的简化示例.
有没有办法将文件末尾的空行读取到变量?
$ rm -f /tmp/a ; for i in $(seq 3) ; do echo $i >> /tmp/a ; done
$ cat /tmp/a
1
2
3
$ wc -l /tmp/a
3 /tmp/a
$ a="$(cat /tmp/a)"
$ echo "$a"
1
2
3
$ echo "$a" | wc -l
3
$ rm -f /tmp/b ; for i in $(seq 3) ; do echo $i >> /tmp/b ; done
$ echo >> /tmp/b # ADD EXTRA EMPTY LINE TO THE END
$ cat /tmp/b
1
2
3
$ wc -l /tmp/b
4 /tmp/b
$ b="$(cat /tmp/b)"
$ echo "$b"
1
2
3
$ echo "$b" | wc -l
3
Run Code Online (Sandbox Code Playgroud)
$(...)剥离所有尾随换行符.从bash手册页:
命令替换允许输出命令来替换命令名称.有两种形式:
Run Code Online (Sandbox Code Playgroud)$(command)要么
Run Code Online (Sandbox Code Playgroud)`command`Bash通过执行命令并用命令的标准输出替换命令替换来执行扩展,删除任何尾随换行符.嵌入的换行不会被删除,但在分词时可能会被删除.命令替换
$(cat file)可以替换为等效但更快$(< file).
用于mapfile在保留换行符的同时读取整个文件.它将每一行读入一个数组.
$ mapfile b < /tmp/b
$ printf '%s' "${b[@]}"
1
2
3
$ printf '%s' "${b[@]}" | wc -l
4
Run Code Online (Sandbox Code Playgroud)
避免echo,这会增加额外的换行符.printf '%s'不这样做,所以你得到了数组中的确切内容.
如果不需要数组,可以使用printf -v它将其展平为单个字符串,同时保留换行符.
$ mapfile b < /tmp/b
$ printf -v b '%s' "${b[@]}"
$ printf '%s' "$b"
1
2
3
$ printf '%s' "$b" | wc -l
4
Run Code Online (Sandbox Code Playgroud)
出于性能原因,我将文件读取到变量,然后使用此变量进行所有处理.这允许我只读取一次文件.
这可能是过早的优化.从磁盘读取文件后,操作系统会将其保留在缓存中.重新读取仍在缓存中的文件非常快.