读取可能不以换行符结尾的面向行的文件

Tim*_*Tim 22 shell bash text-processing newlines

我有一个名为的文件/tmp/urlFile,其中每行代表一个 url。我正在尝试从文件中读取如下内容:

cat "/tmp/urlFile" | while read url
do
    echo $url
done
Run Code Online (Sandbox Code Playgroud)

如果最后一行不以换行符结尾,则不会读取该行。我想知道为什么?

是否可以读取所有行,无论它们是否以新行结束?

Sté*_*las 23

你会这样做:

while IFS= read -r url || [ -n "$url" ]; do
  printf '%s\n' "$url"
done < url.list
Run Code Online (Sandbox Code Playgroud)

(实际上,该循环在最后一行(非)行上添加了丢失的换行符)。

也可以看看:


ilk*_*chu 7

好吧,read如果它在换行符之前遇到文件结束符,则返回一个假值,但即使遇到这种情况,它仍然会分配它读取的值。因此,我们可以检查最终调用是否read返回空行以外的内容,并正常处理它。因此,只有在read返回 false并且该行为空后才退出循环:

#!/bin/sh
while IFS= read -r line || [ "$line" ]; do 
    echo "line: $line"
done

$ printf 'foo\nbar' | sh ./read.sh 
line: foo
line: bar
$ printf 'foo\nbar\n' | sh ./read.sh 
line: foo
line: bar
Run Code Online (Sandbox Code Playgroud)


Dop*_*oti 6

这似乎部分解决了readarray -t

readarray -t urls "/tmp/urlFile"
for url in "${urls[@]}"; do
    printf '%s\n' "$url"
done
Run Code Online (Sandbox Code Playgroud)

但是请注意,虽然这对于合理大小的文件确实有效,但此解决方案在非常大的文件中引入了一个潜在的新问题 - 它首先将文件读入一个数组,然后必须对其进行迭代。对于非常大的文件,这可能既消耗时间又消耗内存,可能会导致故障点。


Gil*_*il' 6

根据定义,文本文件由一系列行组成。甲线以换行符结束。因此文本文件以换行符结尾,除非它是空的。

read内建只是为了阅读的文本文件。您没有传递文本文件,因此您不能希望它能够无缝工作。shell 读取所有行——它跳过的是最后一行之后的额外字符。

如果您有一个潜在的格式错误的输入文件,可能缺少最后一行,您可以向其中添加一个换行符,只是为了确保。

{ cat "/tmp/urlFile"; echo; } | …
Run Code Online (Sandbox Code Playgroud)

应该是文本文件但缺少最后换行符的文件通常由 Windows 编辑器生成。这通常与 Windows 行结尾结合使用,即 CR LF,而不是 Unix 的 LF。CR 字符很少在任何地方有用,并且在任何情况下都不能出现在 URL 中,因此您应该删除它们。

{ <"/tmp/urlFile" tr -d '\r'; echo; } | …
Run Code Online (Sandbox Code Playgroud)

如果输入文件格式正确并且确实以换行符结尾,echo则会添加一个额外的空行。由于 URL 不能为空,因此只需忽略空行。

另请注意,read这不会以直接的方式读取行。它忽略前导和尾随空格,这对于 URL 来说可能是可取的。它将行尾的反斜杠视为转义字符,导致下一行与第一个减去反斜杠-换行符序列连接,这绝对是不可取的。所以你应该将-r选项传递给read. read做正确的事而不是做正确的事是非常非常罕见的read -r

{ <"/tmp/urlFile" tr -d '\r'; echo; } | while read -r url
do
  if [ -z "$url" ]; then continue; fi
  …
done
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

19416 次

最近记录:

5 年,12 月 前