在ls -Q中未正确引用换行符

时间:2016-08-14 00:44:41

标签: linux bash sh ls quoting

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

示例(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’

3 个答案:

答案 0 :(得分:2)

coreutils 8.25拥有全新的shell-escape'引用样式,实际上默认情况下允许ls的输出始终可用,并且可以安全地复制并粘贴回其他命令。

答案 1 :(得分:0)

也许不是你想要的,但“逃避”风格似乎适用于${...@E} 4.4中即将进行的bash参数扩展。

$ 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 :(得分:0)

通过一些实验,看起来--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)按两种版本的预期工作。)