查找和转换以CRLF结尾的文件
1. 概述
在 Linux 中,以回车换行 (CRLF) 结尾的文件在处理时可能会导致一些麻烦。
在本教程中,我们将学习如何找到这些文件并将行尾转换为 LF。
2. 创建示例文件
首先,让我们创建一组示例文件来测试我们的策略:
$ mkdir -p /tmp/test_folder
这样,我们就创建了我们的测试文件夹。让我们分别用两个以 CRLF 和 LF 结尾的文件来填充它:
$ printf "Hi \r\n" | tee /tmp/test_folder/crlf_ending{1,2}
Hi
$ printf "Hi \n" | tee /tmp/test_folder/lf_ending{1,2}
Hi
在第一个单行中,我们创建了两个名为 crlf_ending1和crlf_ending2的文件。两个文件都填充了消息“Hi”,并以 CRLF 行结尾。
在第二个中,我们将其设置为相同,但使用 LF 行结尾和它们各自的文件名。
3. 搜索带有 CRLF 结尾的文件
有几种方法可以使用 Linux 命令查找以 CRLF 结尾的文件。
3.1. cat
让我们从cat :命令开始
$ cat -A /tmp/test_folder/{crlf_ending1,lf_ending1}
Hi ^M$
Hi $
在这里,我们可以通过使用使cat显示非打印字符的*-A*参数来查看两个文件的区别。
3.2. grep
现在,让我们尝试使用grep 命令:
$ grep -rIl -m 1 $'\r' /tmp/test_folder/
/tmp/test_folder/crlf_ending2
/tmp/test_folder/crlf_ending1
我们来看看论据:
- -r,递归读取整个文件夹
- -I,忽略二进制文件
- *-l,*仅打印匹配文件的名称
- -m 1,在第一场比赛后停止阅读
3.3. file
此外,我们可以使用file 命令来提取信息:
$ file /tmp/test_folder/*
/tmp/test_folder/crlf_ending1: ASCII text, with CRLF line terminators
/tmp/test_folder/crlf_ending2: ASCII text, with CRLF line terminators
/tmp/test_folder/lf_ending1: ASCII text
/tmp/test_folder/lf_ending2: ASCII text
3.4. dos2unix
dos2unix命令 是完成这项任务的好工具,但并非总是安装在所有 Linux 发行版中。
要在基于 Debian 的系统上安装它,我们可以输入:
$ sudo apt-get install dos2unix
接下来,为了获取有关行尾的信息,让我们使用-i*参数*中包含的一个不错的功能:
$ dos2unix -i /tmp/test_folder/*
1 0 0 no_bom text /tmp/test_folder/crlf_ending1
1 0 0 no_bom text /tmp/test_folder/crlf_ending2
0 1 0 no_bom text /tmp/test_folder/lf_ending1
0 1 0 no_bom text /tmp/test_folder/lf_ending2
在这里,在第一列和第二列中,我们可以分别看到 DOS 和 Unix 换行符的数量。
4. 将 CRLF 转换为 LF
现在我们已经学习了如何识别带有 CRLF 行结尾的文件,让我们使用一些工具将 CRLF 转换为 LF。
4.1. sed命令
sed命令 是一个很好的文本处理工具。让我们用它来查找和替换crlf_ending1文件中的行尾:
$ sed 's/\r//' /tmp/test_folder/crlf_ending1 | cat -A -
Hi $
在此示例中,我们使用sed命令*’s/\r//’*来查找 \r 字符并将其替换为空值。
此外,如果我们想内联编辑文件,我们可以使用-i*参数*。
最后,通过使用cat命令,我们可以看到没有*^M*字符的最终输出。
4.2. tr命令
tr命令 是一个简单而 强大的工具,可以删除或翻译字符。 让我们使用参数 -d删除*\r*字符:
$ tr -d '\r' < /tmp/test_folder/crlf_ending1 | cat -A -
Hi $
4.3. awk工具
此外,我们可以使用awk 工具删除 \r字符:
$ awk 'gsub(/\r/,"")' /tmp/test_folder/crlf_ending1 | cat -A -
Hi $
在这里,我们使用gsub函数 进行替换。然后,通过省略该操作,awk打印带有替换的整个记录。
4.4. Perl
**我们也可以在我们的场景中使用Perl 解释器和sed: **
$ perl -pe 's/\r//' /tmp/test_folder/crlf_ending1 | cat -A -
Hi $
让我们仔细看看参数:
- -p,用于读取每一行
- -e ’s/\r//’,输入将删除*\r*字符的脚本
4.5. dos2unix
同样,我们可以使用 dos2unix 工具来保持简单。
现在,让我们在示例文件中使用它:
$ dos2unix /tmp/test_folder/crlf_ending1
dos2unix: converting file /tmp/test_folder/crlf_ending1 to Unix format...
我们来看看文件的内容:
$ cat -A /tmp/test_folder/crlf_ending1
Hi $
我们可以看到 CRLF 行尾已经转换为 LF。
最后,让我们恢复我们的文件:
$ unix2dos /tmp/test_folder/crlf_ending1
unix2dos: converting file /tmp/test_folder/crlf_ending1 to DOS format..
最后一点,如果我们只想看到转换后的内容而不实际更改文件,我们可以使用重定向 :
$ dos2unix < /tmp/test_folder/crlf_ending1 | cat - -A
Hi $
4.6. recode
recode 是一个有趣的工具,可以在字符集之间转换文件。
让我们在我们的文件中使用它:
$ recode CP1252...UTF-8 /tmp/test_folder/crlf_ending1
在这里,我们将文件从 CP1252(或 Windows-1252)编码转换为 UTF-8。 现在,让我们看看内容:
$ cat -A /tmp/test_folder/crlf_ending1
Hi $
最后,让我们将文件转换为之前的编码:
$ recode UTF-8...CP1252 /tmp/test_folder/crlf_ending1
4.7. 使用 Vim 编辑器
要使用vim 将 CRLF 行尾转换为 LF ,让我们打开我们的文件:
$ vim /tmp/test_folder/crlf_ending1
现在,我们可以输入 ESC + “:” 进入命令模式。
然后,我们将键入set ff=unix 并按 ENTER。
最后,让我们按 ESC + ZZ 退出并保存文件。
我们来看看内容:
$ cat -A /tmp/test_folder/crlf_ending1
Hi $
要恢复我们的文件,我们可以重复前面的步骤,但输入set ff=dos。
4.8. 使用 Bash 内置
最后,让我们使用一些 bash 内置函数来转换行尾:
$ while read line
do
echo "${line/$'\r'/}"
done < /tmp/test_folder/crlf_ending1 | cat -A
结果,我们应该看到:
Hi $
在这种情况下,我们用我们的测试文件提供了while循环。然后,我们使用参数扩展来删除\r*字符*。
5.同时查找和转换文件
现在我们知道了如何查找带有 CRLF 行结尾的文件并将它们转换为 LF,我们可以将这些操作结合起来。
首先,我们可以避免查找文件,而是直接将dos2unix或sed等命令应用于整个文件夹或模式:
$ dos2unix /tmp/test_folder/crlf_ending*
dos2unix: converting file /tmp/test_folder/crlf_ending1 to Unix format...
dos2unix: converting file /tmp/test_folder/crlf_ending2 to Unix format...
使用 sed:
$ sed -i 's/\r//' /tmp/test_folder/crlf_ending*
但是,如果我们只想转换带有 CRLF 结尾的文件,我们可以使用/xargs 命令组合一些工具:
$ grep -rIl -m 1 $'\r' /tmp/test_folder/ | xargs -P0 -I {} dos2unix {}
让我们使用另一种组合:
$ file /tmp/test_folder/* \
| awk -F : '/CRLF/ && $0=$1' \
| xargs -P0 -I {} sed -i 's/\r//' {}
在这里,我们使用 awk 仅列出仅包含 CRLF 结尾的每个文件的名称。