代码之家  ›  专栏  ›  技术社区  ›  Mathias Bynens

如果文件末尾没有换行符,如何使用while read(Bash)读取文件的最后一行?

  •  45
  • Mathias Bynens  · 技术社区  · 14 年前

    假设我有以下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 我刚才的循环,即没有硬编码输入文件的位置?

    7 回复  |  直到 12 年前
        1
  •  14
  •   netcoder    14 年前

    在你的第一个例子中,我假设你在阅读 . 要对第二个代码块执行相同的操作,只需删除重定向并回显$REPLY:

    DONE=false
    until $DONE ;do
    read || DONE=true
    echo $REPLY
    done
    
        2
  •  39
  •   Jahid Ramsy de Vos    9 年前

    while IFS= read -r LINE || [[ -n "$LINE" ]]; do
        echo "$LINE"
    done
    

    除了输入中的空字符外,它几乎可以处理任何其他内容:

    • 以空行开头或结尾的文件
    • 以空白开头或结尾的行
    • 没有终止换行符的文件
        3
  •  5
  •   Jahid Ramsy de Vos    9 年前

    grep 使用while循环:

    while IFS= read -r line; do
      echo "$line"
    done < <(grep "" file)
    

    grep . 而不是 grep "" 将跳过空行。

    1. 使用 IFS= 保持任何线缩进的完整性。

    2. You should almost always use the -r option with read.

        4
  •  3
  •   prabhakaran9397    8 年前

    而不是 ,尝试使用 GNU核心 喜欢 , 等等。

    readvalue=$(tee)
    echo $readvalue
    

    从文件

    readvalue=$(cat filename)
    echo $readvalue
    
        5
  •  2
  •   Olli K    7 年前

    这是我一直使用的模式:

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

    while 循环结束为 read 用非零代码退出, 阅读 仍然填充内置变量 $REPLY (或您选择使用的任何变量)

        6
  •  1
  •   vaab    9 年前

    最基本的问题是 read 当遇到EOF时将返回errorlevel 1,即使它仍然正确地馈送变量。

    所以你可以使用 在你的循环中,otherwize,最后的数据不会被解析。但你可以这样做:

    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 echo -n 一旦检测到EOF(您可以使用条件 [ "$eof" == true ] )
        7
  •  0
  •   unsynchronized    8 年前

    @Netcoder的答案是好的,这种优化消除了虚假的空行,也允许最后一行没有换行符,如果这是原来的方式。

    DONE=false
    NL=
    until $DONE ;do
    if ! read ; then DONE=true ; NL='-n ';fi
    echo $NL$REPLY
    done
    

    我用它的一个变体创建了两个函数来允许包含“[”的文本管道来让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
     }