更改文件中的列分隔符

更改文件中的列分隔符

我有一个大文件,我需要处理它,在编写了一些似乎无法正常工作的脚本后,我发现文件中的一小部分行实际上是空格分隔的,而不是制表符分隔的。

问题:我想知道将这些空格分隔行更改为制表符分隔行的最佳方法是什么?

该文件每行包含 4 个条目,总共约 5000 个条目,其中约 150 个条目是空格分隔而不是制表符分隔。

答案1

tr ' ' '\t' < file 1<> file

将用制表符替换每个空格字符。


只是为了回应人们说它不安全:

shell 将打开文件以在文件描述符 0 上进行读取,并在文件描述符 1 上进行读写。如果其中任何一个失败,它将退出,tr甚至不会被执行。如果重定向成功,tr则执行。

tr将一次读取文件的一个块,进行音译并输出修改后的块而不是未修改的块。

这样做时,通常不需要在磁盘上分配任何空间。例外情况是文件一开始就稀疏,或者文件系统实现了写时复制。因此,不太可能出现“没有可用空间”的错误。

如果底层磁盘发生故障,或者文件系统位于精简配置的块设备上(如 LVM 快照),则可能会出现其他错误,例如 I/O 错误,这两种情况都很罕见,并且无论如何都可能涉及带来返回备份。

无论如何,当write()系统调用失败时,tr应该报告错误并退出。因为它的stdout是以读写模式打开的,所以它会不是被截断。对于要截断的文件,tr必须truncate()在退出时显式调用其标准输出,这是没有意义的。

但会发生的情况是文件将被部分音译(直到tr失败)。

但我发现tr目前在 Debian sid amd64 上找到的 GNU 有一个漏洞因为它会在系统write()调用失败时出现段错误,并在标准输出上输出垃圾(编辑, 现在自 libc6 Debian 软件包版本 2.19-1 起已修复)。这实际上会损坏文件(但同样不会截断它)。

tr ' ' '\t' < file > newfile && mv newfile file

file除非已正确创建,否则不会替换newfile,但存在许多与之相关的问题:

  • 你需要确保你不会破坏已经存在的newfile(也可以考虑符号链接)
  • 您需要对当前目录的写权限
  • 您需要额外的存储空间来存储该文件的额外副本
  • 您将失去原始文件的权限、所有权、出生时间、扩展属性......
  • 如果原始文件是符号链接,您将用常规文件替换它。

tr ' ' '\t' < file 1<> file比常用的更安全,perl -pi -e 's/ /\t/g'因为一旦发生故障perl(例如磁盘已满),您将丢失原始文件,并且只能获得perl到目前为止已成功输出的文件。

答案2

sed也可以使用。

sed -i.bak 's/ /\t/g' filename

这将filename.bak在编辑文件之前创建一个。

s/ /\t/g=> 这告诉sed我们在文件的每一行全局用制表符替换空格。

答案3

要将文件中的每个空格更改为制表符,请使用tr.

tr ' ' '\t' <input_file >output_file

要将一个或多个空格的每个序列更改为单个制表符,请使用sed

sed -e 's/  */\t/g' <input_file >output_file

一些 sed 实现理解\t为制表符,其他实现则需要文字制表符。

如果您有一个包含对齐列的文件,并且使用可变数量的空格来对齐列,则可以将其转换为具有制表符分隔的列unexpand

相关内容