微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么我的工具输出覆盖本身,如何解决?

这个问题的目的是为日常问题提供一个答案,答案是“你有DOS行结束”,所以我们可以简单地将它们作为这个副本closures,而不必重复相同的答案和恶心 。

注意: 这不是任何现有问题的重复 。 这个问答的目的不仅仅是提供一个“运行这个工具”的答案,而且是为了解释这个问题,这样我们就可以在这里指出任何有相关问题的人,他们也会find一个明确的解释,说明他们为什么被指出来作为运行的工具来解决他们的问题。 我花了数小时阅读所有现有的问答,他们都缺乏对问题的解释,可以用来解决问题的替代工具,和/或可能的解决scheme的优点/缺点/警告。 还有一些人已经接受了只是非常危险的答案,不应该被使用。

现在回到可能导致转介的典型问题

我有一个包含1行的文件

join两个文件的第一列

文件格式:使用awk NRvariables混淆

使用Linux删除短于4个字符的单词

用逗号分隔多行代码(Perl / Sed / AWK)

如何在使用awk的文件模式之后打印5个连续的行

what isgoingon

当我使用这个awk脚本打印它来颠倒字段的顺序时:

awk '{print $2,$1}' file

而不是看到我期望的输出

isgoingon what

我得到应该在行尾的字段出现在行首,覆盖行首的一些文本:

whatngon

或者我把输出分成两行:

isgoingon what

有什么问题,我该如何解决

如何使用AWK颠倒字段的顺序?

计算基于时间的指标(每小时)

AWK中的多分裂

用sed打印每个匹配模式的第一行

如何仅在重复行的末尾添加连续数字

问题在于你的输入文件使用的是CRLF DOS行结尾,而不是仅仅是LF的UNIX行尾,而你正在运行一个UNIX工具,所以CR仍然是UNIX工具正在运行的数据的一部分。 CR通常用r表示,并且在LF为n在文件上运行cat -vE时可以看作是一个control-M( ^M ),并且显示为$ with cat -vE 。

所以你的输入文件不是真的只是:

what isgoingon

其实是:

what isgoingonrn

正如你可以看到与cat -v :

$ cat -vE file what isgoingon^M$

和od -c :

$ od -c file 0000000 whatisgoingon r n 0000020

所以当你在文件上运行一个像awk这样的UNIX工具(把n作为行结尾)时, n会被读取行消耗掉,但是会留下2个字段:

<what> <isgoingonr>

请注意第二个字段末尾的r 。 r表示Carriage Return符,实际上是将光标返回到行首的指令,所以当你这样做的时候:

print $2,$1

awk将打印isgoingon ,然后将光标返回到行的开始,然后打印what是为什么似乎覆盖isgoingon的开始。

解决这个问题,请执行以下任一操作:

dos2unix file sed 's/r$//' file awk '{sub(/r$/,"")}1' file perl -pe 's/r$//' file

显然, dos2unix在某些UNIX变种(例如Ubuntu)中也是frodos 。

如果你决定使用tr -d 'r' ,那么要小心,因为这会删除文件中的所有文件,而不是每行结尾的文件

请注意,GNU awk将让您通过简单地设置RS解析具有DOS行结尾的文件

gawk -v RS='rn' '...' file

但是其他的awks不允许这样做,因为POSIX只需要awks来支持单个字符RS,而其他大多数awks都会静静地截断RS='rn'到RS='r' 。 您可能需要为gawk添加-v BINMODE=3来查看r s,因为底层的C原语会在某些平台上剥离它们,例如cygwin。

需要注意的一点是,像Excel这样的Windows工具创建的CSV将使用CRLF作为行尾,但可以将LF嵌入到CSV的特定字段中,例如:

"field1","field2.1 field2.2","field3"

是真的:

"field1","field2.1nfield2.2","field3"rn

所以如果您只是将rn s转换为n s,则您不能再将换行符中的换行符作为换行结束符,因此如果您想这样做,我建议先将所有的换行符换行转换为其他的换行符,例如,这会将所有内部字段LFs转换为制表符,并将所有结束CRLF的行转换为LF s:

gawk -v RS='rn' '{gsub(/n/,"t")}1' file

在没有GNU awk的情况下进行类似的练习只是一个练习,但是在其他awk中,它涉及到在读取时不结束CR行。

运行dos2unix 。 虽然你可以用自己编写的代码来操作行结尾,但Linux / Unix世界中已经存在的实用程序已经为你做了这些工作。

如果在Fedora系统上, dnf install dos2unix会把dos2unix工具放在适当位置(不应该安装)。

Debian系统有一个类似的dos2unix deb软件包。

从编程的角度来看,转换很简单。 搜索文件中的所有字符以获取序列rn并将其替换为n 。

这意味着使用几乎所有可以想象的工具,都有几十种从DOS转换到Unix的方法一个简单的方法就是使用命令tr ,只要简单地用r替换就可以了!

tr -d 'r' < infile > outfile

您可以在PCRE中使用R 简写字符类来处理未知行尾的文件。 在Unicode或其他平台上,还有更多线路需要考虑。 R表单是来自Unicode联合体的推荐字符类,用于表示所有形式的通用换行符。

所以,如果你有一个额外的,你可以找到并删除正则表达式s/R$/n/将标准化行结束的任何组合n 。 或者,您可以使用s/R/n/g来捕获任何“行结束”的概念并将其标准化为n字符。

鉴于:

$ printf "whatrisgoingonrn" > file $ od -c file 0000000 what risgoingon r n 0000020

Perl和Ruby以及PCRE的多数风格实现R结合字符串断言的结束$ (多行模式下的行尾):

$ perl -pe 's/R$/n/' file | od -c 0000000 what risgoingon n 0000017 $ ruby -pe '$_.sub!(/R$/,"n")' file | od -c 0000000 what risgoingon n 0000017

(注意两个单词之间的r是正确的单独)

如果您没有R您可以在PCRE中使用相同的(?>rn|v) 。

有了POSIX的直接工具,你最好的选择可能就是这样:

$ awk '{sub(/r$/,"")} 1' file | od -c 0000000 what risgoingon n 0000017

事情有点工作(但知道你的局限性):

tr删除所有r即使在另一个上下文中使用(授予r很少使用,而且XML处理要求r被删除,所以tr是一个很好的解决方案):

$ tr -d "r" < file | od -c 0000000 whatisgoingon n 0000016

GNU sed工作,但不支持POSIX sed因为r和x0D在POSIX上不受支持

GNU sed only:

$ sed 's/x0D//' file | od -c # also sed 's/r//' 0000000 what risgoingon n 0000017

Unicode正则表达式指南可能是对“新行”进行明确处理的最佳选择。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐