Contents

从文件中删除每行结尾换行符

1. 概述

使用 Linux 命令行时的一项常见任务是搜索字符串或模式,然后替换或删除它。然而,有一些特殊的字符可以使这个常见的任务没有我们预期的那么简单。

在本教程中,我们将探讨使用trawkPerlpastesed、 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 文件。

我们可以借助内置的readarrayIFS变量和参数扩展机制来实现相同的目的:

$ 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 将其应用于文件的所有行。