Regex 仅当条件适用时,才在bash中删除非ascii字符
我有一个非常具体的需求,我一直在努力解决,但没有成功 我有一个日志,它是由tcp/ip套接字转储创建的。。。它将十六进制转换为ASCII,但其中自然有一些特殊字符 我已经设法删除了它们,但我目前遇到了一个困难:有时会发送0x0A,这会干扰我的应用程序。。。我试图删除它,但它同时也删除了行末尾的有效0x0A 基本上,我在日志文件中:Regex 仅当条件适用时,才在bash中删除非ascii字符,regex,bash,awk,sed,hex,Regex,Bash,Awk,Sed,Hex,我有一个非常具体的需求,我一直在努力解决,但没有成功 我有一个日志,它是由tcp/ip套接字转储创建的。。。它将十六进制转换为ASCII,但其中自然有一些特殊字符 我已经设法删除了它们,但我目前遇到了一个困难:有时会发送0x0A,这会干扰我的应用程序。。。我试图删除它,但它同时也删除了行末尾的有效0x0A 基本上,我在日志文件中: 08-14-2017 10:00:00 String={Teste String} 08-14-2017 10:00:00 String={ Teste String
08-14-2017 10:00:00 String={Teste String}
08-14-2017 10:00:00 String={
Teste String2}
08-14-2017 10:00:00 String={
Teste String3}
08-14-2017 10:00:00 String={Teste String4}
我想要最后的结果
08-14-2017 10:00:00 String={Teste String}
08-14-2017 10:00:00 String={Teste String2}
08-14-2017 10:00:00 String={Teste String3}
08-14-2017 10:00:00 String={Teste String4}
字符始终在{}之间,因此}之后的每个0x0A都有效,但内部无效
我尝试的每个命令要么删除所有0x0A,要么根本不起作用
我试过这样的方法
sed 's/^[^}]*}//'
sed 's/\x0A$//'
有什么想法吗 这在sed中当然是可能的,但在awk中更容易阅读和理解:
awk 'BEGIN{ OFS=FS="{"; ORS=RS="}" } { sub(/[^[:print:]]/,"",$2) } 1' input.txt
这有什么用?
- 首先,我们将输入和输出字段分隔符设置为
,将输入和输出记录分隔符设置为{
。这让我们可以预测地将括号内的文本作为一个特定字段(至少基于您的示例数据)}
- 接下来,我们用空字符串替换字段#2中的任何不可打印字符,从而消除换行符、退格等
- 最后,我们使用awk速记打印该行
- 这当然可以通过sed实现,但在awk中更容易阅读和理解:
awk 'BEGIN{ OFS=FS="{"; ORS=RS="}" } { sub(/[^[:print:]]/,"",$2) } 1' input.txt
这有什么用?
- 首先,我们将输入和输出字段分隔符设置为
,将输入和输出记录分隔符设置为{
。这让我们可以预测地将括号内的文本作为一个特定字段(至少基于您的示例数据)}
- 接下来,我们用空字符串替换字段#2中的任何不可打印字符,从而消除换行符、退格等
- 最后,我们使用awk速记打印该行
- 带sed的
Linux:
$ sed -r ':a;N;$!ba;s/(\{[^}]*)\\n([^{]*\})/\1\2/g' file
08-14-2017 10:00:00 String={Teste String}
08-14-2017 10:00:00 String={Teste String2}
08-14-2017 10:00:00 String={Teste String3}
08-14-2017 10:00:00 String={Teste String4}
FreeBSD和macOS:
sed -e ':a' -e 'N;$!ba' -e 's/(\{[^}]*)\\n([^{]*\})/\1\2/g' file
解释
-e':a'-e'N;$!BA’/代码>允许我们在SED的每次迭代中同时考虑当前和下一行。有关详细信息,请参阅
(\{[^}]*)
确保左大括号后面没有右大括号
([^{]*\})
的作用正好相反。使用sed:
Linux:
$ sed -r ':a;N;$!ba;s/(\{[^}]*)\\n([^{]*\})/\1\2/g' file
08-14-2017 10:00:00 String={Teste String}
08-14-2017 10:00:00 String={Teste String2}
08-14-2017 10:00:00 String={Teste String3}
08-14-2017 10:00:00 String={Teste String4}
FreeBSD和macOS:
sed -e ':a' -e 'N;$!ba' -e 's/(\{[^}]*)\\n([^{]*\})/\1\2/g' file
解释
-e':a'-e'N;$!BA’/代码>允许我们在SED的每次迭代中同时考虑当前和下一行。有关详细信息,请参阅
(\{[^}]*)
确保左大括号后面没有右大括号
([^{]*\})
的作用正好相反。Perl:
$ perl -0777 -pe 's/({[^}]*)\x0A([^}]*})/\1\2/g' file
08-14-2017 10:00:00 String={Teste String}
08-14-2017 10:00:00 String={Teste String2}
08-14-2017 10:00:00 String={Teste String3}
08-14-2017 10:00:00 String={Teste String4}
纯Bash(基于anubhava的awk):
而IFS=“\n”读取-r行;做
le=“”
[[$line=~\}]&&le=$'\n'
printf“%s%s”$line“$le”
完成Perl:
纯Bash(基于anubhava的awk):
而IFS=“\n”读取-r行;做
le=“”
[[$line=~\}]&&le=$'\n'
printf“%s%s”$line“$le”
完成另一个更简单的awk
:
awk '{printf "%s%s", $0, (/}/ ? ORS : "")}' file
08-14-2017 10:00:00 String={Teste String}
08-14-2017 10:00:00 String={Teste String2}
08-14-2017 10:00:00 String={Teste String3}
08-14-2017 10:00:00 String={Teste String4}
此awk
命令检查一行中是否存在}
,然后只打印换行符,否则将打印不带换行符的记录。另一个更简单的awk
:
awk '{printf "%s%s", $0, (/}/ ? ORS : "")}' file
08-14-2017 10:00:00 String={Teste String}
08-14-2017 10:00:00 String={Teste String2}
08-14-2017 10:00:00 String={Teste String3}
08-14-2017 10:00:00 String={Teste String4}
此awk
命令检查一行中是否存在}
,然后只打印换行符,否则将打印不带换行符的记录。对于多字符,使用GNU awk,我们只需隔离每个{…}
字符串并删除其中的换行符即可:
$ awk -v RS='{[^}]+}' '{ORS=gensub(/\n/,"","g",RT)}1' file
08-14-2017 10:00:00 String={Teste String}
08-14-2017 10:00:00 String={Teste String2}
08-14-2017 10:00:00 String={Teste String3}
08-14-2017 10:00:00 String={Teste String4}
对于这种特定的情况,其他awk答案将很好地工作,以上只是隔离分隔字符串的问题的一个更一般的解决方案,然后对其执行操作,就像在这种情况下删除字符一样。对于多字符的GNU awk,我们可以只隔离每个{…}
字符串并删除其中的换行符:
$ awk -v RS='{[^}]+}' '{ORS=gensub(/\n/,"","g",RT)}1' file
08-14-2017 10:00:00 String={Teste String}
08-14-2017 10:00:00 String={Teste String2}
08-14-2017 10:00:00 String={Teste String3}
08-14-2017 10:00:00 String={Teste String4}
对于这种特殊情况,其他awk答案也可以,以上只是隔离分隔字符串,然后对其执行操作(如本例中删除字符)问题的更一般解决方案。您是在ASCII文本上应用sed命令还是在十六进制上应用sed命令?在ASCII文本上……您是在ASCII文本上应用sed命令还是在十六进制上应用sed命令?在ASCII文本上……不是吗在FreeBSD或macOS中为我工作。这是GNU sed特有的吗?当您将其拆分时,它会起作用:sed-E-E':a'-E'N;$!ba'-e's/(\{[^}]*)\n([^{]*\})/\1\2/g'
。。非GNU sed似乎希望标签后面不要跟分号。@ghoti谢谢。我更新了。这应该适用于GNU-sed和非GNU-sed(?)。\n
不能跨sed版本移植(您需要反斜杠后跟文字换行符以便于移植),-E
只能在GNU和OSX-sed中工作,而-r
只能在GNU-sed中工作。此外,Solaris 10中的sed不支持-E
或-r
,因此最好使用基于BRE的解决方案以实现最大的可移植性。在bash中,您可以使用格式替换获得嵌入的文字换行符,即$'foo\nbar'
。在FreeBSD或macOS中不适用于我。这是GNU sed特有的吗?当您将其拆分时,它会起作用:sed-E-E':a'-E'N;$!ba'-e's/(\{[^}]*)\n([^{]*\})/\1\2/g'
。。非GNU sed似乎希望标签后面不要跟分号。@ghoti谢谢。我更新了。这应该适用于GNU-sed和非GNU-sed(?)。\n
不能跨sed版本移植(您需要反斜杠后跟文字换行符以便于移植),-E
只能在GNU和OSX-sed中工作,而-r
只能在GNU-sed中工作。此外,Solaris 10中的sed不支持-E
或-r
,因此最好使用基于BRE的解决方案以实现最大的可移植性。在bash中,可以获得嵌入的文本newli