脚本无法读取文件的最后一行

6

我有一个使用记事本在Windows上创建的文件:

    26453215432460
    23543265235421

    38654365876325


    12354152435243

我有一个脚本,它会读取每一行,并为每一行创建以下命令,不考虑空行:

    CRE:EQU,264532154324600,432460,1;

现在,如果我在输入最后一行数字12354152435243后按下回车键保存我的输入文件,则输出文件将包含所有数字(包括最后一个12354152435243)对应的以上命令:

    CRE:EQU,264532154324600,432460,1;
    CRE:EQU,235432652354210,235421,1;
    CRE:EQU,386543658763250,876325,1;
    CRE:EQU,123541524352430,435243,1;

但是,如果我在最后一个数字键入后没有按回车键就保存文件,也就是在这个12354152435243之后,那么在脚本执行后,我不会看到输出文件有关于最后一个数字的命令:

    CRE:EQU,264532154324600,432460,1;
    CRE:EQU,235432652354210,235421,1;
    CRE:EQU,386543658763250,876325,1;

请问有人能解释一下代码中的错误吗:

    while read LINE
    do
    [ -z "$LINE" ] && continue
    IMEI=`echo $LINE | sed 's/ //g' | sed -e 's/[^ -~]//g'`
    END_SERIAL=`echo $IMEI | cut -c9- | sed 's/ //g' | sed -e 's/[^ -~]//g'`
    echo "CRE:EQU,${IMEI}0,${END_SERIAL},${list},,${TODAY};" >> /apps/ins/list.out
    done < "${FILE_NAME}"

kindly help


我想知道这是否与Windows和*nix的行结尾有关。 (可能不是,但你永远不知道...)尝试在像HexFiend这样的十六进制编辑器中打开文件,并查看最后一个字符。 - daviewales
是的,我在考虑使用回车或\n字符。 - hax0r_n_code
在我的脚本中已经添加了 dos2unix,在获取输入文件后。你的意思是,这样做不够吗? - dig_123
1
记事本有一个愚蠢的想法,即最后一行不需要任何类型的终止符。如果您没有确保手动以换行符结束文件,则保存的内容在技术上不是有效的文本文件,因为文本文件由带有终止符的行组成。 - user2404501
是的,我已经明白了 :( - dig_123
显示剩余3条评论
5个回答

6

使用

grep . "${FILE_NAME}" | while read LINE

或者

while read LINE
do
....
done < <(grep . "${FILE_NAME}")

grep命令对于行结尾不太敏感,你将得到一个自由跳过空行的结果... :)

说实话,我从未尝试过在Windows上使用,以上所有内容都适用于Unix...

编辑说明:

创建下一个文件:

echo -n -e 'line\n\nanother\nno line ending here>' >file.txt

该文件包含4行文本(尽管最后一行不是“正确”的)

line

another
no line ending here>

通常的Shell例程,如readwc,都会寻找行尾。因此,
$ wc -l file.txt 
         3 file.txt

当你使用''(空字符串)进行grep时,它会返回包含该字符串的每一行,因此

$ grep '' file.txt

打印

line

another
no line ending here>

当 grep 打印出找到的行时,确保最后存在一个 `\n'。
$ grep '' file.txt | wc -l

返回值

4

因此,在这些情况下,最好使用带有 -c(计数)的 grep 而不是 wc
$ grep -c '' file.txt
4

现在,点.。点代表任何字符。因此,当您使用grep查找.时,您会得到所有包含至少一个字符的行。因此,它将跳过不包含任何字符的行=跳过空行。所以,
$ grep . file.txt
line
another
no line ending here>

再次强调,上一行末尾需要添加换行符(并跳过空行)。请记住,(空格)也是一个字符,因此当一行只包含一个空格时,它并不是空行。计算非空行。

$ grep . file.txt | wc -l
      3

或更快

$ grep -c . file.txt
3

太好了,这个可行。您能否友善地解释一下为什么我要从$FILE中grep .的逻辑?无论如何,非常感谢这个技巧。干杯! - dig_123
@Siddharth 添加了解释。 - clt60

1

read会一直读取直到找到一个新行,当它找到一个新行时,它会返回这一行。但是如果文件没有新行结束,read将把其视为错误。因此,即使read已经设置了返回变量为到目前为止读取的行,read的返回代码也被设置为指示错误。现在while read ...循环体仅在命令执行成功时执行,而这里不是这种情况。因此你会错过最后一行。

为了克服这个问题,你可以改变条件以检查返回变量是否为空。因此,即使read失败,条件也会成功,因为变量已经设置到文件的末尾。

这与不同操作系统中的换行符不相关,我是说它与某种程度上有关,但确切的根本原因始终是read无法在行/文件结尾找到新行,导致最后一行缺失循环体。

下面是一个例子:

[[bash_prompt$]]$ echo -ne 'hello\nthere' > log
[[bash_prompt$]]$ while read line; do  echo $line; done < log
hello
[[bash_prompt$]]$ while read line || [ -n "$line" ]; do  echo $line; done < log
hello
there
[[bash_prompt$]]$

1
如果你执行help read,它会说对于-d delim,读取将持续到读取DELIM的第一个字符,而不是换行符。因此,读取将持续到遇到\n或者指定了-d delim为止。所以你可能需要更改delim,或者尝试使用read -e

“read -e” 对我无效,“echo -n $'a\nb' | while read -e x ; do echo $x ; done” “-ksh: read: -e: unknown option Usage: read [-ACprsv] [-d delim] [-u fd] [-t timeout] [-n nchar] [-N nchar] [var?prompt] [var ...]” 并且,使用 -d 选项的 delim 会增加我代码的长度,因为我必须先将输入文件复制一份,并在每个非空行上使用一个字符作为分隔符,然后将其提供给 read -d delim - dig_123

0

read需要读取输入的行末。请尝试:

echo -n $'a\nb' | while read x ; do echo $x ; done

它只打印a


read -e 对我不起作用:echo -n $'a\nb' | while read -e x ; do echo $x ; done -ksh: read: -e: 未知选项 用法:read [-ACprsv] [-d delim] [-u fd] [-t timeout] [-n nchar] [-N nchar] [var?prompt] [var ...] 它在 k-shell 中不起作用吗? - dig_123
@Siddharth:-e 不重要,我只是在尝试 nkon 建议的内容。 - choroba

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接