我有一个在最后一行末尾没有EOL的文件。当我从中读取的bash脚本没有处理最后一行时,我注意到了这一点。
我是这样读的:
while read LINE
do
...
done <thefile
该文件是提供给我的,因此在它登陆我的系统之前我无能为力(Linux - OpenSuSE 10.2)。我在文件上运行dos2unix
,但这不能解决丢失的EOL。
我看过几个涉及vi
和ed
的解决方案,但它们有点笨重,我希望有一个更简洁的解决方案,可能使用sed
,我可以在我的bash脚本中使用?
奇怪的是,当我vi
该文件并执行:set list
时,我可以在最后一行的末尾看到“$
”。因为我认为“$
”代表\n
,所以我期待失踪。或者换行和行尾之间可能存在差异?
答案 0 :(得分:5)
如果文件的末尾没有(并且不是空白),可以选择在文件末尾添加换行符:
if [ -s "$thefile" ] && [ "$(tail -c1 "$thefile"; echo x)" != $'\nx' ]; then
echo >>"$thefile"
fi
或者,这是一种简单的方法来修改循环以处理最终换行之后的任何内容:
while read LINE || [ -n "$LINE" ]
do
...
答案 1 :(得分:3)
这会在文件末尾添加换行符:
echo >> thefile
答案 2 :(得分:2)
sed -i -e '$a\' "path"
只会在EOF上添加换行符(如果它还没有换行符)(跳转后的解释)。
如果你想处理可能在EOF没有换行符的文件,你必须检查循环后read
输出变量是否存在:
while read LINE
do
...
done <thefile
if [ "${LINE+defined}" = defined ]
then
...
fi
不是很优雅,但至少在处理输入之前不必修改输入。
答案 3 :(得分:1)
多个实用程序在输出结尾添加换行符。例如,您可以使用cut并执行:
cut -b 1- < thefile |
while read LINE; do ...; done
(可能并非所有剪切的实现都像我描述的那样,但很多都是。)
罗伯特的解决方案可能最简单,如果你无法真正更改文件,你可以这样做:
{ cat thefile; echo; } | while read ...
请注意,将while放入管道会将其置于子进程中,这可能会对脚本产生影响(例如,循环中的赋值将不会持久),因此您可能需要使用临时文件或命名管道修改数据。
答案 4 :(得分:0)
[ -n "$l" ]
可以替换为[[ $l ]]
。 [[ $l ]]
相当于[[ -n $l ]]
。不必引用$l
,因为不会在[[
内执行分词和路径名扩展。
$ printf 'x\ny' | while IFS= read -r l; do echo "$l"; done
x
$ printf 'x\ny' | while IFS= read -r l || [[ $l ]]; do echo "$l"; done
x
y
仅当文件以换行符结尾或为空时, $(tail -c1)
才为空。 $()
从末尾删除换行符,tail -c1
为空文件为空。 -s
测试文件是否存在且不为空。
f=/tmp/some\ file
[[ -s $f && $(tail -c1 "$f") ]] && printf \\n >> "$f"
sed -n p
(无打印,打印)是sed '$a\'
的替代方案。 BSD seds需要-i ''
而不仅仅是-i
。
sed -i '' -n p *.txt