【问题标题】:Newlines not quoted properly in ls -Qls -Q 中没有正确引用换行符
【发布时间】:2016-12-20 15:55:20
【问题描述】:

ls -Q--quoting-style=shell 一起使用,文件名中的换行符(是的,我知道...)会变成?。这是一个错误吗?有没有办法以与 shell 100% 兼容的格式获取文件名(如果可能,使用 sh 或 bash)?

示例(bash):

$ touch a$'\n'b
$ for s in literal shell shell-always c c-maybe escape locale clocale ; do
      ls -Q a?b --quoting-style=$s
  done
a?b
'a?b'
'a?b'
"a\nb"
"a\nb"
a\nb
‘a\nb’
‘a\nb’

【问题讨论】:

  • --quoting-style="escape"--quoting-style="c" 应该可以工作...
  • @l'L'l:它没有。 eval ls $(ls -Q --quoting-style=escape) 产生ls: cannot access anb: No such file or directory,所以它不会往返。如果没有eval,它也不起作用。
  • c 可能是你最好的选择......而且任何时候你 eval ls 然后 ls 在一个子shell中它都会得到奇怪的结果。
  • @l'L'l,--quoting-style=shell 的全部意义在于生成eval 可以正确解析的内容。这是一个明显的错误。
  • @CharlesDuffy:报告为24225

标签: linux bash sh ls quoting


【解决方案1】:

也许不是您想要的,但“转义”样式似乎与bash 4.4 中即将推出的${...@E} 参数扩展配合得很好。

$ touch $'a\nb' $'c\nd'
$ ls -Q --quoting-style=escape ??? | while IFS= read -r fname; do echo =="${fname@E}==="; done
==a
b==
==c
d==

这是man page 的相关部分(链接指向原始来源):

${parameter@operator}
          Parameter transformation.  The expansion is either a transforma-
          tion  of  the  value of parameter or information about parameter
          itself, depending on the value of operator.  Each operator is  a
          single letter:

          Q      The  expansion is a string that is the value of parameter
                 quoted in a format that can be reused as input.
          E      The expansion is a string that is the value of  parameter
                 with  backslash  escape  sequences  expanded  as with the
                 $'...' quoting mechansim.
          P      The expansion is a string that is the result of expanding
                 the value of parameter as if it were a prompt string (see
                 PROMPTING below).
          A      The expansion is a string in the form  of  an  assignment
                 statement  or  declare  command  that, if evaluated, will
                 recreate parameter with its attributes and value.
          a      The expansion is a string consisting of flag values  rep-
                 resenting parameter's attributes.

          If  parameter  is @ or *, the operation is applied to each posi-
          tional parameter in turn, and the  expansion  is  the  resultant
          list.   If  parameter is an array variable subscripted with @ or
          *, the case modification operation is applied to each member  of
          the array in turn, and the expansion is the resultant list.

          The  result  of  the  expansion is subject to word splitting and
          pathname expansion as described below.

【讨论】:

  • 找不到解释,有链接吗?
  • 我找不到;我将复制手册页的相关部分。
【解决方案2】:

通过一些实验,看起来--quoting-style=escape 与被包裹在$'...' 中是兼容的,但有两个例外:

  • 它通过添加反斜杠来转义空格;但$'...' 不会丢弃空格前的反斜杠。
  • 它不会转义单引号。

所以你也许可以写这样的东西(在 Bash 中):

function ls-quote-shell () {
    ls -Q --quoting-style=escape "$@" \
    | while IFS= read -r filename ; do
        filename="${filename//'\ '/ }"  # unescape spaces
        filename="${filename//"'"/\'}"  # escape single-quotes
        printf "$'%s'\n" "$filename"
      done
}

为了测试这一点,我创建了一个目录,其中包含一堆带有奇怪字符的文件名;和

eval ls -l $(ls-quote-shell)

按预期工作。 . .虽然我不会对此做出任何坚定的保证。

或者,这里有一个版本,它使用printf 处理转义,然后使用printf %q 以对shell 友好的方式重新转义:

function ls-quote-shell () {
    ls -Q --quoting-style=escape "$@" \
    | while IFS= read -r escaped_filename ; do
        escaped_filename="${escaped_filename//'\ '/ }"  # unescape spaces
        escaped_filename="${escaped_filename//'%'/%%}"  # escape percent signs
        # note: need to save in variable, rather than using command
        # substitution, because command substitution strips trailing newlines:
        printf -v filename "$escaped_filename"
        printf '%q\n' "$filename"
      done
}

但如果事实证明在某些情况下第一个版本无法正确处理,那么第二个版本很可能会遇到同样的问题。 (FWIW,eval ls -l $(ls-quote-shell) 在两个版本中都按预期工作。)

【讨论】:

    【解决方案3】:

    coreutils 8.25 具有新的“shell-escape”引用样式,实际上默认启用它以允许 ls 的输出始终可用,并且可以安全地复制和粘贴回其他命令。

    【讨论】:

    • 这也是我从错误报告中得到的。不幸的是,我的盒子上仍然是 8.22 和 8.23。
    猜你喜欢
    • 2016-12-29
    • 2012-11-12
    • 1970-01-01
    • 2012-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多