【问题标题】:Escaping special characters with sed使用 sed 转义特殊字符
【发布时间】:2014-12-24 14:26:04
【问题描述】:

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

#!/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}

这很接近...

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

【问题讨论】:

  • 我会考虑解析od -c的输出而不是使用sed
  • @JV,我想知道你的输出是否真的正确:echo -ne 'test\x12345' | od -c 输出0000000 t e s t 022 3 4 5,将\x12 解释为单个字符,而不是\x12345
  • @nu11p01n73R:这是换行符的 shell 提示符。
  • @glennjackman:我使用 GCC 进行了测试,而逻辑会假定在 2 个字符 GCC 以字符串和字符的形式读取它们之后将其切断,然后执行 mod 0x100。

标签: regex sed


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    这是一个非常复杂的解决方案,但可能会满足您的需求。 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'}
    

    【讨论】:

    • 我喜欢它自动处理转义特殊字符的方式——有没有办法删除输出字符之间的空格?这基本上可以满足我的需求
    • 我在谈论 od 本身 - 有没有办法删除用于分隔字符的缩进?
    • 如果文件包含转义序列(由 GCC 读取),则应将其复制为字符。输入字符串test\ntest\x0A 应该输出{'t','e','s','t','\n','t','e','s','t','\x0A',0} 你的将转义序列拆分为单独的字符
    • 因为wchar_t 在 linux 上是 4 个字节。基本上,如果你想在 linux 上创建一个静态的 win32 unicode 字符串,你需要创建一个字符数组 - 手工操作非常烦人。
    • 这行得通。我有一个使用双 sed 的版本,它的工作原理是这样的:sed -r ':a;N;s/\n/\\n/;$!ba' | sed -r 's/((\\x[0-9a-fA-F]+)|(\\[0-7]{1,3})|(\\?.))/'"'\1',/g" 我只是很生气我必须使用双 sed(使用 ; 会因为某种原因破坏它)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-09
    • 2019-05-14
    • 2011-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多