Contents

查找和转换以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_ending1crlf_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,我们可以将这些操作结合起来。

首先,我们可以避免查找文件,而是直接将dos2unixsed等命令应用于整个文件夹或模式

$ 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 结尾的每个文件的名称