我有一个bash函数,该函数将文件作为参数,验证文件是否存在,然后将标准输入中的所有内容写入文件中。天真的解决方案适用于文本,但我在使用任意二进制数据时遇到问题。
echo -n '' >| "$file" #Truncate the file
while read lines
do # Is there a better way to do this? I would like one...
echo $lines >> "$file"
done
我有一个bash函数,该函数将文件作为参数,验证文件是否存在,然后将标准输入中的所有内容写入文件中。天真的解决方案适用于文本,但我在使用任意二进制数据时遇到问题。
echo -n '' >| "$file" #Truncate the file
while read lines
do # Is there a better way to do this? I would like one...
echo $lines >> "$file"
done
Answers:
您的方法是在任何分隔符($IFS
)用于分隔读取的空间中,将断行符添加到它写入的所有内容中。无需将其分解为换行符,只需将整个过程传递下去。您可以将上面的整个代码缩减为:
cat - > $file
您不需要截断位,这将截断并将整个STDIN流写入其中。
编辑:如果您使用的是zsh,则可以> $file
代替猫使用。您将重定向到文件并截断它,但是如果有任何东西挂在那儿,等待某些东西接受STDIN,它将在那一点被读取。我认为您可以使用bash进行类似的操作,但是必须设置一些特殊模式。
> $file
。这仅是在父shell脚本中查找stdin的第一件事。基本上,David的所有代码都可以简化为一个字符,但是我认为该代码cat -
更优雅,麻烦也更少,因为它是可见的。
cat
cat
只是为数据文件命名,所以坚持使用数据文件的人必须进行精神体操来阅读代码。命名管道也是很好的目标。
要从字面上读取文本文件,请不要使用plain read
,它会以两种方式处理输出:
read
解释\
为转义字符;用于read -r
关闭此功能。read
在文字上分成单词$IFS
; 设置IFS
为空字符串可将其关闭。逐行处理文本文件的惯用法是
while IFS= read -r line; do …
有关此惯用语的说明,请参见为什么while IFS= read
经常使用而不是IFS=; while read..
?。
要从字面上编写字符串,请不要仅使用plain echo
,它会以两种方式处理字符串:
echo
进程反斜杠转义。(在bash上,取决于是否xpg_echo
设置了该选项。)-n
或-e
(确切的设置取决于外壳)。用字面量打印字符串的可移植方式是使用printf
。(bash中没有更好的方法,除非您知道您的输入看起来不像是echo
。的选项。)使用第一种形式打印确切的字符串,如果要添加换行符,则使用第二种形式。
printf %s "$line"
printf '%s\n' "$line"
这仅适用于处理文本,因为:
您无法在Shell中处理二进制数据,但是大多数unices上的现代版本的实用程序都可以处理任意数据。要将所有输入传递到输出,请使用cat
。切线echo -n ''
是一种复杂且不可携带的无所事事的方式。echo -n
一样好(或不取决于外壳),并且:
更简单且完全可移植。
: >| "$file"
cat >>"$file"
或者,更简单地说,
cat >|"$file"
在脚本中,>|
由于noclobber
默认情况下处于关闭状态,因此通常无需使用。
这将完全满足您的要求:
( while read -r -d '' ; do
printf %s'\0' "${REPLY}" ;
done ;
# When read hits EOF, it returns non-zero which exits the while loop.
# That data still needs to be output:
printf %s "${REPLY}"
) >> ${file}
不过要注意内存使用情况。这将以空分隔的方式读取输入。
如果输入中没有\0
空字节,则bash首先需要将输入的全部内容读入内存,然后将其输出。
关于截断步骤:
echo -n '' >| "$file" #Truncate the file
一个简单得多的等效项是:
> ${file} #Truncate the file