显然您在 Windows 机器上编辑了files.txt,然后将其复制到您的 Linux 或 Unix 服务器,而不转换行尾。这不是一个不常见的问题,并且存在多种解决方案。 :)
Windows 使用 CR+LF (\r\n) 换行,而 unix 和 linux 仅使用 LF (\n)。
如果您的复制程序支持这样的事情,第一个也是最简单的选择可能是重新复制文件并进行适当的转换。如果您使用 FTP 协议复制文件,请检查您的客户端是否有“类型”选项,该选项可能设置为“ascii”或“bin”。取决于你的客户。如果你使用像scp 这样的东西,它只传输二进制文件,那么请继续阅读。
另一个经过验证的选项是使用dos2unix 应用程序,它可能已经安装在您的 unix 或 linux 服务器上。如果不是,您可以使用机器的包管理器安装它。 (我不知道怎么做,因为你没有提到你正在使用什么操作系统。)如果安装,可以通过运行man dos2unix 找到使用dos2unix 的文档。例如,如果你想转换当前目录下所有匹配*.txt的文本文件以及当前目录下的所有子目录,你可以使用如下:
find . -type f -name \*.txt -exec dos2unix -k -o {} \;
这里起作用的选项如下:
-
find . - 告诉 find 从当前目录开始递归搜索。
-
-type f -name \*.txt 按文件类型和 glob 限制我们的搜索。
-
-exec 在每个文件上运行该行的其余部分,直到 \;,并将 {} 替换为文件名。
-
dos2unix - 嗯,你知道的。
-
-k - “保留”原始文件的时间戳。
-
-o - 编辑“原始”文件而不是编写新文件。
如果 dos2unix 不可用,许多其他内置工具可能能够完成类似的工作。
如果您运行的是 Linux,则可以像这样在一个文件上使用 GNU sed:
sed -i 's/\r$//' files.txt
或者处理当前目录下的所有文本文件:
for file in *.txt; do sed -i 's/\r$//' "$file"; done
如果您使用的是 bash 版本 4 或更高版本,或者以递归方式运行:
shopt -s globstar
for file in **/*.txt; do sed -i 's/\r$//' "$file"; done
转换行尾的另一种选择可能是 perl:
perl -pi -e 's/\r\n/\n/g' files.txt
如果需要,您可以轻松地使其处理一个目录中的多个文件,或者以与上述选项类似的方式递归处理。
另一种选择可能是保留文件原样,并在 bash 中处理 files.txt 时进行转换。例如:
while read line; do
find . -name "${line%$'\r'}"
done < files.txt > outfile.txt
这使用 shell 的参数扩展与 bash 的格式扩展相结合,在您的 while 循环读取每个变量时“剥离”有问题的 CR 字符。
还要注意: