更改文件中的列分隔符

Sti*_*ham 7 text-processing columns

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

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

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

Sté*_*las 9

tr ' ' '\t' < file 1<> file
Run Code Online (Sandbox Code Playgroud)

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


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

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

tr 将一次一个块地读取文件,进行音译并在未修改的块上输出修改的块。

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

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

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

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

但我发现,tr目前在 Debian sid amd64 上发现的 GNU有一个错误,它会在write()系统调用失败时出现段错误,并在 stdout 上输出垃圾(编辑,现在已从 libc6 Debian 软件包的 2.19-1 版开始修复) . 这实际上会损坏文件(但同样不会截断它)。

tr ' ' '\t' < file > newfile && mv newfile file
Run Code Online (Sandbox Code Playgroud)

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

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

tr ' ' '\t' < file 1<> file比常用的更安全,perl -pi -e 's/ /\t/g'因为在失败perl(如磁盘已满)时,您将丢失原始文件,并且只能获得perl到目前为止已设法输出的内容。