如何在Ubuntu中更改许多文件中的^ L代码?


8

我有很多XML文件,其中超过50000个。

在某些XML文件中,某些文件是这样写的

<filename>abc.JPEG<^Lilename>

^L只是一个字符,但我找不到^LGoogle意味着什么。

当我cat用来打印文件的内容时,它显示如下

<filename>abc.JPEG<
                   ilename>

无论如何,我想更改<filename>abc.JPEG<^Lilename><filename>abc.JPEG</filename>

我已经找到了一些命令来更改许多文件中的单词,例如

find . -exec perl -pi -e 's/[find_word]/[change_word]/g' {} \;

但是该命令在我的情况下不起作用,因为在我键入时它无法识别搜索词^L

如何更改<filename>abc.JPEG<^Lilename><filename>abc.JPEG</filename>多个文件?


6
显然有人使用<\filename>而不是</filename>在上下文\f中将其解释为换页符。您可能应该跟踪这些文件的来源,并向开发人员指出其生成工具的问题。对于修复文件,可以接受答案。
汉斯·马丁·莫斯纳

Answers:


17

Control-L(表示为^L)是“换页”字符。在ASCII中,它的十进制值为12(L是字母的第12个字母)或十六进制值为0c:

$ printf 'foo\x0cbar\n' | cat -et
foo^Lbar$

$ printf 'foo\x0cbar\n'
foo
   bar

您可以使用sed之类的工具通过指定十六进制转义码来替换它:

$ printf 'foo\x0cbar\n' | sed 's/\x0c//'
foobar

或者,^L直接使用键盘序列CTRL+ V CTRL+编写L

sed 's/CTRL+VCTRL+L//'

对于您的特定替换,给定

$ printf '<\x0cilename\n'
<
 ilename

然后

$ printf '<\x0cilename\n' | sed 's/<\x0c/<\/f/g'
</filename

g如果每行有一个以上实例,则添加修饰符)。


就我而言,“ $ printf'<\ x0cilename \ n'| sed's / <\ x0c / <\\ f / g'”不起作用。但是,根据您的回答,“ $ find。-exec perl -pi -e's / <\ x0cilename> / <\ / filename> / g'{} \;”;效果很好。感谢您的回答:)

@Yang对不起,我才意识到我在答案中混淆了正斜杠和反斜杠(现已更正)-仍不确定为什么这会阻止sed版本的工作
-steeldriver

一个很好的答案!如果它包含一个“说” find,它将遍历那些50000个XML文件并自动处理每个文件(并进行备份),那会更好。
金斯利

2

正如汉斯·马丁·莫斯纳(Hans-Martin Mosner)在评论中指出的那样,似乎有人在生成XML时使用了反斜杠而不是正斜杠(或者可能是整个<filename>节段都对反斜杠过于热衷)。\f是换页符(即U + 0C或^ L)很少使用的转义序列。因此,管道的后续步骤随后将\fU 替换为文字U + 0C字符。

幸运的是,U + 0C是一个极为罕见的字符,不太可能在任何XML中被有意发现。而且,由于仅\f会产生这一点,而不是(说)\g或者\k,通用查找和替换应该修复不仅</filename></folder></file>或其他任何东西,得到了错位。

这就是Steeldriver的sed脚本所做的;我只想稍微概括一下:

sed 's|\x0c|/f|g'

这意味着“将(\x0cU + 0C)的所有实例都/f遍历为(g)叶”。


2

\f是Perl中的换页符。这些格式错误的文件似乎是由Perl和XML的新手创建的。

这是一个Perlier修复程序-它也满足了OP自动更新所有文件的目标,这与sed可接受的答案不同,因为sed一次只能与一个文件配对,因此只能使用一个文件find

\f本身可以简单地代替十六进制代码使用x0c

find . -type f -exec perl -pi.bkp -e 's [ \f ilename ][ /f ilename ]gx' {} \;

在这里,我已经添加-type f到tel中find,只返回普通文件-否则find将返回.列表,并在尝试编辑它时触发警告,尽管其他所有操作仍然可以进行。

通过使用x忽略真实空格的标志,我还使正则表达式更易于查看,从而使您可以将正则表达式的元素隔开。如果您不喜欢这样,这里就没有:

find . -type f -exec perl -pi.bkp -e 's[\filename][/filename]g' {} \;

并且在所有可能的换页字符都是虚假的情况下,所有字符都应替换为/f,那么您可以进一步缩小单行格式:

find . -type f -exec perl -pi.bkp -e 's[\f][/f]g' {} \;

您不需要使用正斜杠将s///Perl中的regex替换命令的元素()括起来。您可以使用任何符号。但是,如果选择使用任何一种成对的类似括号的符号,则必须同时使用它们:s[old][new]例如。

由于我不使用斜杠,因此我不必转义任何斜杠。

至于-i.bkpperl -pi -e让您就地编辑-但是如果您想要额外的保险以防万一您发现并替换了Perl程序错误,则可以放入文件扩展名,以便为该文件复制原始文件。您。在这里,我用过.bkp

在最新版本的Perl中,就地编辑已更新为更具弹性,以防您的系统也遇到严重的问题,例如断电或磁盘空间不足。这是Perl的作者brian d foy在最近的Perls中改进的就地编辑。

您应该考虑使用Perl对于这些类型的任务,因为它是一个非常强大但被低估的通用编程语言,其最初的设计目标是取代的一个sed,并awk与东西要好得多。

Perl 5的regex匹配功能和改进的regex语法远远超过了sedawk以及除Perl 6之外的所有其他编程语言,使Perl成为简单和高级regex操作的最明智的选择。

需要说明的是:sed也可以正常工作find,您还可以使用sed -i.bkp它为每个编辑过的文件做备份,但据我所知,它在Perl 5.28及更高版本中没有额外的弹性。它还使用了笨拙且功能较弱的传统UNIX®正则表达式语法。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.