仅在条件适用时删除非ascii字符,在bash中

时间:2017-08-14 13:52:16

标签: regex bash awk sed hex

我有一个非常具体的需求,我一直试图解决这个问题,但没有成功。

我有一个日志,它是通过转储tcp / ip套接字创建的......它将Hex转换为ASCII,但自然会有一些特殊字符。

我已设法删除它们,但我目前遇到了一个困难:有时候会发送一个0x0A,这会混淆我的应用程序......我正在尝试将其删除,但之后它也会删除有效行尾的0x0A ......

基本上,我在日志文件中有:

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$//'

任何想法?

5 个答案:

答案 0 :(得分:3)

另一个更简单 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命令检查一行中是否存在},然后只打印换行符,否则打印出不带换行符的记录。

答案 1 :(得分:1)

这对于sed来说当然是可能的,但在awk中更容易阅读和理解:

awk 'BEGIN{ OFS=FS="{"; ORS=RS="}" } { sub(/[^[:print:]]/,"",$2) } 1' input.txt

这是做什么的?

  • 首先,我们将输入和输出字段分隔符设置为{,将输入和输出记录分隔符设置为}。这让我们可以预测地将括号内的文本作为特定字段(至少基于您的示例数据)获取。
  • 接下来,我们将字段#2中的任何不可打印字符替换为空字符串,从而消除换行符,退格键等。
  • 最后,我们使用awk简写打印线。

答案 2 :(得分:1)

使用GNU awk for multi-char RS,我们可以隔离每个{...}字符串并删除其中的换行符:

$ 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答案将正常工作,上面只是一个更通用的解决方案,解决了分隔分隔字符串然后对它执行操作的问题,就像在这种情况下删除字符一样。

答案 3 :(得分:0)

使用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的每次迭代中考虑当前行和下一行。有关详细信息,请参阅this SO answer

(\{[^}]*)确保有一个开口大括号后面没有结束大括号。

([^{]*\})则恰恰相反。

答案 4 :(得分:0)

的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}

Pure Bash(基于anubhava的awk):

while IFS="\n" read -r line; do 
    le=""
    [[ $line =~ \} ]] && le=$'\n'
    printf "%s%s" "$line" "$le"
done <file