代码之家  ›  专栏  ›  技术社区  ›  Amandasaurus

如何在bash中反向转义反斜杠编码,如“\”和“\303\266”?

  •  3
  • Amandasaurus  · 技术社区  · 15 年前

    我有一个用utf8编码名称记录文件的脚本。然而,脚本的编码/环境设置不正确,它只是重新编码原始字节。我现在在文件中有很多这样的行:

    .../My\ Folders/My\ r\303\266m/...
    

    所以文件名中有空格 \ 和utf8编码的东西,比如 \303\266 (这是 ö )我想反转这个编码?是否有一些简单的bash命令行命令集可以链接在一起以删除它们?

    我可以得到数百万 sed 命令,但是列出我们拥有的所有非ASCII字符需要很长时间。或者开始用python解析它。但我希望我能做点什么。

    6 回复  |  直到 6 年前
        1
  •  5
  •   Dennis Williamson    6 年前

    下面是对Unicode字符的粗略分析:

    text="/My\ Folders/My\ r\303\266m/"
    text="echo \$\'"$(echo "$text"|sed -e 's|\\|\\\\|g')"\'"
    # the argument to the echo must not be quoted or escaped-quoted in the next step
    text=$(eval "echo $(eval "$text")")
    read text < <(echo "$text")
    echo "$text"
    

    这就利用了 $'string' 引用bash的特性。

    这将输出“/my folders/my r_¶m/”。

    从bash 4.4开始,它非常简单:

    text="/My Folders/My r\303\266m/"
    echo "${text@E}"
    

    这使用了bash的一个新特性 parameter transformation . 这个 E 运算符使参数被视为其内容在内部 “串” 其中反斜杠转义序列,在本例中是八进制值。

        2
  •  2
  •   mark4o    15 年前

    目前还不清楚具体使用的是哪种逃逸方式。八进制字符代码是C,但C不转义空格。空间转义在shell中使用,但它不使用八进制字符转义。

    使用命令可以撤消接近C样式转义的操作 printf %b $escaped . (文件上说八进制溢出从 \0 ,但这似乎不是GNU printf所要求的。)另一个答案提到 read 对于未捕获的外壳,尽管只有空间不被处理 printf %b 然后用 sed 可能会更好。

        3
  •  1
  •   Amandasaurus    15 年前

    最后我用了这样的方法:

    cat file | sed 's/%/%%/g' | while read -r line ; do printf "${line}\n" ; done | sed 's/\\ / /g'
    

    一些文件 % 在它们中,这是一个printf特殊字符,所以我必须将其“加倍”,以便它可以被转义并直接通过。这个 -r 在里面 read 停止读取转义 \ 但是读不转 "\ " 进入之内 " " 所以我需要决赛 sed .

        4
  •  1
  •   sorontar    8 年前

    使用 printf 用UTF-8文本解决这个问题。使用 read 注意空间 (\ ) .

    这样地:

    $ text='/My\ Folders/My\ r\303\266m/'
    $ IFS='' read t < <(printf "$text")
    $ echo "$t"
    /My Folders/My röm/
    
        5
  •  0
  •   William Pursell    15 年前

    内置的“read”函数将处理 问题:

    $ echo "with\ spaces" | while read r; do echo $r; done
    with spaces
    
        6
  •  0
  •   NawaMan    15 年前

    将文件(逐行)传递给以下Perl脚本。

    #!/usr/bin/per
    
    sub encode {
        $String = $_[0];
        $_ = $String;
        while(/(\\[0-9]+|.)/g) {
            $Match = $1;
    
            if ($Match =~ /\\([0-9]+)/) {
                $Code = oct(0 + $1);
                $Char = ((($Code >= 32) && ($Code  160))
                    ? chr($Code)
                    : sprintf("\\x{%X}", $Code);
                printf("%s", $Char);
            } else {
                print "$Match";
            }
        }
    
        print "\n";
    }
    
    while ($#ARGV >= 0) {
        $File = shift();
        open(my $F, ") {
            $String =~ s/\\ / /g;
            &encode($Line);
        }
    }
    

    这样地:

    $ ./PerlEncode.pl Test.txt
    

    其中test.txt包含:

    /My\ Folders/My\ r\303\266m/
    /My\ Folders/My\ r\303\266m/
    /My\ Folders/My\ r\303\266m/
    

    行“$string=~s/\/g;”将“\”替换为“”,然后对这些Unicode字符进行子编码。

    希望这有帮助