用sed转义特殊字符

时间:2014-12-24 14:26:04

标签: regex sed

我有一个脚本从字符串生成char数组:

#!/bin/bash
while [ -n "$1" ]
do
    echo -n "{" && echo -n "$1" | sed -r "s/((\\\\x[0-9a-fA-F]+)|(\\\\[0-7]{1,3})|(\\\\?.))/'\1',/g" && echo "0}"
    shift
done

它的效果很好:

$ wchar 'test\n' 'test\\n' 'test\123' 'test\1234' 'test\x12345'
{'t','e','s','t','\n',0}
{'t','e','s','t','\\','n',0}
{'t','e','s','t','\123',0}
{'t','e','s','t','\123','4',0}
{'t','e','s','t','\x12345',0}

但是因为sed认为每个新行都是一个全新的东西,它不能处理实际的新行:

$ wchar 'test
> test'
{'t','e','s','t',
't','e','s','t',0}

如何使用转义版本替换特殊字符(制表符,换行符等),以便输出如下:

$ wchar 'test
> test'
{'t','e','s','t','\n','t','e','s','t',0}

编辑:一些几乎有用的想法:

echo -n "{" && echo -n "$1" | sed -r ":a;N;;s/\\n/\\\\n/;$!ba;s/((\\\\x[0-9a-fA-F]+)|(\\\\[0-7]{1,3})|(\\\\?.))/'\1',/g" && echo "0}"

产地:

$ wchar 'test\n\\n\1234\x1234abg
test
test'
{test\n\\n\1234\x1234abg\ntest\ntest0}

删除!

echo -n "{" && echo -n "$1" | sed -r ":a;N;;s/\\n/\\\\n/;$ba;s/((\\\\x[0-9a-fA-F]+)|(\\\\[0-7]{1,3})|(\\\\?.))/'\1',/g" && echo "0}"

产地:

$ wchar 'test\n\\n\1234\x1234abg
test
test'
{'t','e','s','t','\n','\\','n','\123','4','\x1234ab','g','\n','t','e','s','t',
test0}

这很接近......

第一个没有执行最后的替换,第二个没有正确添加最后一行

2 个答案:

答案 0 :(得分:3)

您可以在传递给sed之前进行预过滤。 Perl会这样做:

$ set -- 'test1
> test2'
$ echo -n "$1" | perl -0777 -pe 's/\n/\\n/g'
test1\ntest2

答案 1 :(得分:1)

这是一个非常复杂的解决方案,但可能适合您的需求。 GNU awk 4.1

#!/usr/bin/awk -f
@include "join"
@include "ord"
BEGIN {
  RS = "\\\\(n|x..)"
  FS = ""
}
{
  for (z=1; z<=NF; z++)
    y[++x] = ord($z)<0x20 ? sprintf("\\x%02x",ord($z)) : $z
  y[++x] = RT
}
END {
  y[++x] = "\\0"
  for (w in y)
    y[w] = "'" y[w] "'"
  printf "{%s}", join(y, 1, x, ",")
}

结果

$ cat file
a
b\nc\x0a

$ ./foo.awk file
{'a','\x0a','b','\n','c','\x0a','\0'}