Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 如果存在’;文件末尾没有换行符吗?_Bash_Newline_Eof - Fatal编程技术网

Bash 如果存在’;文件末尾没有换行符吗?

Bash 如果存在’;文件末尾没有换行符吗?,bash,newline,eof,Bash,Newline,Eof,假设我有以下Bash脚本: while read SCRIPT_SOURCE_LINE; do echo "$SCRIPT_SOURCE_LINE" done 我注意到,对于结尾没有换行符的文件,这将有效地跳过最后一行 我四处寻找解决方案: 当读取到达文件末尾时 在行尾,它在 数据并将其分配给变量, 但它以非零状态退出。 如果您的循环是“while”构造的 阅读;做事;完成 因此,与其测试读取出口 直接状态,测试一个标志,并具有 read命令从中设置该标志 在环体内。那样 无论读取退出状态

假设我有以下Bash脚本:

while read SCRIPT_SOURCE_LINE; do
  echo "$SCRIPT_SOURCE_LINE"
done
我注意到,对于结尾没有换行符的文件,这将有效地跳过最后一行

我四处寻找解决方案:

当读取到达文件末尾时 在行尾,它在 数据并将其分配给变量, 但它以非零状态退出。 如果您的循环是“while”构造的 阅读;做事;完成 因此,与其测试读取出口 直接状态,测试一个标志,并具有 read命令从中设置该标志 在环体内。那样 无论读取退出状态如何 整个循环体运行,因为读取 只是命令列表中的一个 像其他人一样,在循环中,而不是 决定循环是否运行的因素 跑吧

DONE=false
until $DONE ;do
read || DONE=true
# process $REPLY here
done < /path/to/file.in
DONE=false
直到完成;做
read | | DONE=true
#在这里处理$REPLY
完成

如何重写此解决方案,使其行为与我之前使用的
循环完全相同,即不硬编码输入文件的位置?

在第一个示例中,我假设您正在从stdin读取。要对第二个代码块执行相同的操作,您只需删除重定向和echo$REPLY:

DONE=false
until $DONE ;do
read || DONE=true
echo $REPLY
done

我使用以下构造:

while IFS= read -r LINE || [[ -n "$LINE" ]]; do
    echo "$LINE"
done
除了输入中的空字符外,它几乎可以处理任何内容:

  • 以空行开头或结尾的文件
  • 以空格开头或结尾的行
  • 没有终止换行符的文件

这里的基本问题是,
read
遇到EOF时将返回errorlevel 1,即使它仍然正确地输入变量

因此,您可以在循环中立即使用errorlevel of
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
记住:

  • NUL字符将被忽略
  • 如果您坚持使用
    echo
    模仿
    cat
    的行为,则需要在检测到EOF时强制执行
    echo-n
    (您可以使用条件
    [“$EOF”==true]

使用
grep
和while循环:

while IFS= read -r line; do
  echo "$line"
done < <(grep "" file)
当IFS=read-r行时;执行
回音“$line”

完成<@Netcoder的答案是好的,这种优化消除了虚假的空行,还允许最后一行没有换行,如果原来是这样的话

DONE=false
NL=
until $DONE ;do
if ! read ; then DONE=true ; NL='-n ';fi
echo $NL$REPLY
done
我使用了它的一个变体来创建两个函数,允许包含“[”的文本管道,以使grep满意。(您可以添加其他翻译)

(传递-由于$1启用管道,否则只转换参数)

请尝试使用GNU Coreutils,如tee、cat等,而不是read

来自stdin

readvalue=$(tee)
echo $readvalue
从文件

readvalue=$(cat filename)
echo $readvalue

这是我一直使用的模式:

while read -r; do
  echo "${REPLY}"
done
[[ ${REPLY} ]] && echo "${REPLY}"

这是因为即使
循环结束时
读取
的“test”以非零代码退出,
read
仍然填充内置变量
$REPLY
(或您选择用
读取
指定的任何变量).

啊,重定向让我很困惑。谢谢你的回答,它就像一个符咒!如果有最后一行换行符,要避免处理额外的(空)行,请在包含
读取
[!$REPLY]]的行后添加此内容&&continue
@Dennis:这似乎跳过了所有的空行,这正是我在本例中想要的。谢谢!您不需要在IFS中包含换行符;您只需将其设置为空字符串即可。此外,要使此POSIX兼容(目前它只在bash中工作,而不是
/bin/sh
),请执行
IFS=''read-r LINE | |[-n“$LINE”]
注意,如果EOF中还没有换行符,则会在EOF中添加一个额外的换行符。第三条注意:POSIX标准就是这样定义一行的(第3206行):
while read -r; do
  echo "${REPLY}"
done
[[ ${REPLY} ]] && echo "${REPLY}"