假设我有以下Bash脚本:
while read SCRIPT_SOURCE_LINE; do
echo "$SCRIPT_SOURCE_LINE"
done
我注意到,对于最后没有换行的文件,这将有效地跳过最后一行。
我一直在寻找解决方案and found this:
当读取到达文件结尾时 在行尾,它确实在读取 数据并将其分配给变量, 但它以非零状态退出。 如果你的循环是“同时构建的” 阅读;做事;完成
所以不要测试读取退出 状态直接,测试一个标志,并有 read命令设置该标志来自 在循环体内。那样 无论读取退出状态如何 整个循环体运行,因为阅读 只是命令列表中的一个 在循环中像任何其他,而不是 决定循环的因素 完全运行。
DONE=false until $DONE ;do read || DONE=true # process $REPLY here done < /path/to/file.in
如何重写此解决方案,使其行为与我之前使用的while
循环完全相同,即不对输入文件的位置进行硬编码?
答案 0 :(得分:34)
我使用以下构造:
while IFS= read -r LINE || [[ -n "$LINE" ]]; do
echo "$LINE"
done
除了输入中的空字符外,它几乎可以使用任何东西:
答案 1 :(得分:13)
在你的第一个例子中,我假设你正在阅读 stdin 。要对第二个代码块执行相同操作,您只需删除重定向并回显$ REPLY:
DONE=false
until $DONE ;do
read || DONE=true
echo $REPLY
done
答案 2 :(得分:5)
将grep
与while循环一起使用:
while IFS= read -r line; do
echo "$line"
done < <(grep "" file)
使用grep .
代替grep ""
将跳过空行。
注意:
使用IFS=
可以保持任何行缩进。
末尾没有换行符的文件不是标准的unix文本文件。
答案 3 :(得分:2)
而不是读取,尝试使用 GNU Coreutils ,如 tee , cat 等。
来自stdin
readvalue=$(tee)
echo $readvalue
来自档案
readvalue=$(cat filename)
echo $readvalue
答案 4 :(得分:1)
这里的基本问题是read
在遇到EOF时会返回错误级别1,即使它仍然正确地提供变量。
因此,你可以立即在你的循环中使用read
的错误级别,其他文件,最后的数据不会被解析。但你可以这样做:
eof=
while [ -z "$eof" ]; do
read SCRIPT_SOURCE_LINE || eof=true ## detect eof, but have a last round
echo "$SCRIPT_SOURCE_LINE"
done
如果你想要一种非常可靠的方法来解析你的行,你应该使用:
IFS='' read -r LINE
请记住:
echo
来模仿cat
的行为,则需要在检测到EOF时强制echo -n
(您可以使用条件{{1} })答案 5 :(得分:0)
@Netcoder的答案很好,这种优化消除了虚假的空白行,也允许最后一行没有换行符,如果原来是这样的话。
DONE=false
NL=
until $DONE ;do
if ! read ; then DONE=true ; NL='-n ';fi
echo $NL$REPLY
done
我使用了它的一个变体来创建2个函数,以允许包含'['的文本管道以保持grep快乐。 (您可以添加其他翻译)
function grepfix(){
local x="$@";
if [[ "$x" == '-' ]]; then
local DONE=false
local xx=
until $DONE ;do
if ! IFS= read ; then DONE=true ; xx="-n "; fi
echo ${xx}${REPLY//\[/\\\[}
done
else
echo "${x//\[/\\\[}"
fi
}
function grepunfix(){
local x="$@";
if [[ "$x" == '-' ]]; then
local DONE=false
local xx=
until $DONE ;do
if ! IFS= read ; then DONE=true ; xx="-n "; fi
echo ${xx}${REPLY//\\\[/\[}
done
else
echo "${x//\\\[/\[}"
fi
}
(传递 - 因为$ 1启用管道,否则只是翻译参数)
答案 6 :(得分:0)
这是我一直在使用的模式:
while read -r; do
echo "${REPLY}"
done
[[ ${REPLY} ]] && echo "${REPLY}"
哪个有效,因为即便如此while
循环结束为&#34; test&#34;从read
退出非零代码,read
仍会填充内置变量$REPLY
(或您选择使用read
分配的任何变量)。