从文件中删除每行结尾换行符
1. 概述
使用 Linux 命令行时的一项常见任务是搜索字符串或模式,然后替换或删除它。然而,有一些特殊的字符可以使这个常见的任务没有我们预期的那么简单。
在本教程中,我们将探讨使用tr、awk、Perl、paste、sed、 Bash 和 Vim 编辑器等工具删除换行符的几种方法。
2.准备我们的示例文件
在我们开始之前,让我们创建一个名为some_names.txt的文本文件,我们将使用它来应用我们所有的策略:
$ cat > some_names.txt << _eof_
Martha,
Charlotte,
Diego,
William,
_eof_
目标是最终得到一个类似 CSV 的文件,其内容如下:
Martha,Charlotte,Diego,William,
3.使用tr
要删除某些字符或用特定的其他字符替换某些字符,我们会想到tr ,因为它易于使用。
命令tr 使用标准输入 ( stdin ),执行一些操作(翻译、压缩、删除),然后将结果复制到标准输出 ( stdout )。
我们现在将重点放在“删除”操作上。使用参数*-d*,我们定义了一组我们希望tr删除的字符。
因为我们只想删除换行符,所以我们只将这个字符放在集合中,然后将标准输出重定向到一个新的 CSV 文件:
$ tr -d "\n" < some_names.txt > some_names.csv
现在,让我们看看 CSV 文件的内容:
$ cat some_names.txt
Martha,Charlotte,Diego,William,
4.使用awk
awk 程序 是一个众所周知的、强大的、有用的工具,它允许我们使用模式和动作来处理文本。
它让我们借助一些技巧以非常直接的方式执行一些操作:
$ awk 1 ORS='' some_names.txt > some_names.csv
让我们看看 CSV 文件的内容:
$ cat some_names.csv
Martha,Charlotte,Diego,William,
让我们仔细看看我们是如何解决这个问题的。
我们编写模式“1”是因为它的计算结果为true(允许处理记录),然后,在没有操作的情况下,awk执行默认操作,即打印以ORS 变量的值终止的整个记录.
然后我们定义默认设置为换行符的*ORS (输出记录分隔符)*变量为空字符串。
在这两个步骤之后,我们使用了每条记录,然后使用空字符串作为输出记录分隔符打印它们。换句话说,我们只是忽略了换行符。
另一种方法是将其用作awk程序文本:
$ awk 'ORS="";1' some_names.txt
一个扩展版本是:
$ awk 'BEGIN{ ORS="" } { print $0 }' some_names.txt
在这里,我们做同样的事情,但是这次,我们使用BEGIN 模式,它在读取任何输入之前执行定义ORS变量的操作,然后打印包含整个记录(通常是一个记录)的*$0*变量 输入的整行)。
5. 使用 Perl
Perl 是一种具有大量文本处理功能的语言。
我们将以类似sed的方式使用 Perl 解释器:
$ perl -pe 's/\n//' some_names.txt > some_names.csv
让我们看一下这个命令是如何工作的:
- -p 告诉 Perl 假设我们的程序有以下循环
- -e 告诉 Perl 使用下一个字符串作为单行脚本
- ’s/\n//’ 是指示 Perl 删除*\n*字符的脚本
现在,让我们回顾一下我们的 CSV 文件:
$ cat some_names.csv
Martha,Charlotte,Diego,William,
6. 使用paste
paste 程序是一个合并文件行的实用程序,但我们也可以用它来删除换行符。
让我们尝试下一个单行:
$ paste -sd "" some_names.txt > some_names.csv
现在,让我们检查我们的 CSV 文件:
$ cat some_names.csv
Martha,Charlotte,Diego,William,
我们之所以能够实现这一点,是因为paste具有参数*-s*,它一次粘贴一个文件,每个文件保持一行,而*-d*允许我们将空字符串定义为分隔符。
有了这两个粘贴选项,我们就可以得到我们想要的而无需提及换行符。
7. 使用sed
当我们谈论处理文本时,无论问题如何,通常都会想到sed 流编辑器。
脚本*’s/pattern/replacement/’通常在sed*中使用。
让我们用它来替换行尾,看看会发生什么:
$ sed 's/\n//g' some_names.txt
Martha,
Charlotte,
Diego,
William,
并且没有任何变化,因为sed一次读取一行,然后在将换行符放入模式空间之前总是将其剥离。
让我们试试这个新的单线:
$ sed ':label1 ; N ; $! b label1 ; s/\n//g' some_names.txt > some_names.csv
接下来,让我们看看我们的 CSV 文件里面有什么:
$ cat some_names.csv
Martha,Charlotte,Diego,William,
现在我们得到了我们想要的。
让我们分解脚本的每个部分(以分号分隔)以了解其工作原理:
- :label1创建一个名为**label1 的标签
- N告诉sed将下一行追加到模式空间
- $!b label1告诉sed分支(转到)我们的标签label1如果不是最后一行
- s/\n//g从模式空间中的内容中删除*\n字符*
换句话说,将所有这些部分放在一起,我们构建了一个循环,该循环在sed位于输入的最后一行时结束。
8. 使用 Bash 命令行脚本
大多数 Linux 发行版都安装了Bash ,所以我们可以尝试使用它来获得我们想要的东西。
我们可以使用的一个选项是while循环:
$ while read row
do
printf "$row"
done < some_names.txt > some_names.csv
在这里,在while循环中,借助 Bash 内置的read,我们读取文件some_names.txt的内容,然后将每一行分配给变量row。
之后,内置的printf打印该行而不带换行符。最后,我们将输出重定向到我们的 CSV 文件。
我们可以借助内置的readarray、 IFS变量和参数扩展机制来实现相同的目的:
$ OLDIFS=$IFS ; IFS='' ; readarray -t file_array < some_names.txt ; echo "${file_array[*]}" > some_names.csv ; IFS=$OLDIFS
Bash 充满了技巧,我们在这里使用了其中的一些技巧。让我们一段一段地理解它:
- OLDIFS = $IFS:我们将当前变量IFS保存到OLDIFS变量中。
- IFS=”:我们将IFS定义为空字符串
- 使用readarray -t file_array … ,我们将**some_names.txt文件的内容分配给数组file_array,从每一行中删除换行符
- 使用*“${file_array[*]}”,Bash 扩展数组file_array的每个值,由**IFS*变量的第一个字符分隔
- 最后,我们恢复IFS变量
但是我们可以使用子 shell 稍微棘手一些:
$ (
readarray -t file_array < some_names.txt;
IFS='';
echo "${file_array[*]}" > some_names.csv;
)
这在保持当前IFS 变量安全的同时是等效的,这要归功于子 shell 内的变量在其外部不可见这一事实。
值得一提的是 IFS变量 比较特殊。Bash IFS变量的默认值为 space tab newline 或“\t\n”。
最后,让我们看看我们的 CSV 文件中现在有什么:
$ cat some_names.csv
Martha,Charlotte,Diego,William,
9. 使用 Vim 编辑器
在 Linux 中,我们有多种编辑器风格,但让我们关注最著名的一种。
Vim (Vi Improved)是一个配备了很多实用工具的编辑器。
让我们在 Vim 编辑器中打开示例文件:
$ vim some_names.txt
Martha,
Charlotte,
Diego,
William,
接下来,让我们编写命令*%s/\n//*并将其保存到我们的 CSV 文件中。
现在,我们有这样的事情:
Martha,Charlotte,Diego,William,
现在,让我们将内容保存到名为some_names.csv的文件中。
为了完成本节,让我们了解发生了什么。使用命令s/\n//,我们删除每个*\n字符。使用%*符号,Vim 将其应用于文件的所有行。