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

使用ls -Q --quoting-style=shell--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' 

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

也许不是你要找的东西,但是“逃避”风格似乎在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== 

这里是手册页的相关部分(链接到原始来源):

 ${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. 

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