禁用从 bash read 内置命令转义字符串中的单引号

disable escaping single quotes within string from bash read builtin command

我想处理来自包含单引号文件名的文本文件的文件,例如

'new'$'\n''line'
'tab'$'\t''ulator'

用于手动处理此文件的复制和粘贴工作正常:

test -f 'tab'$'\t''ulator'


现在,使用 bash 读取内置命令

从文件中读取
while IFS="" read -r myfile; do
  line=$myfile
  ...
done < text.txt

给出包含转义单引号的字符串,如

'\''new'\''$'\''\n'\'''\''line'\'''
'\''tab'\''$'\''\t'\'''\''ulator'\'''

然而,在 bash 脚本中处理此文件名不起作用。

test -f "$myfile"
test -f ${myfile}


如何在 bash?

中禁用/撤消转义单引号和处理原始文件名

找到字符串操作的解决方案

${filename//$'7'\$'7'$'7'/$'7'}

正如您上面提到的,使用 eval 对 'rm -rf' 这样的文件名非常危险。关于 stat -c %N (仅转义单引号、换行符和制表符)还有另一种解决方案

while IFS="" read -r myfile; do

  filename="$myfile"

  filename="${filename#?}"
  filename="${filename%?}"
  filename="${filename//"'$'\t''"/$'1'}"
  filename="${filename//"'$'\n''"/$'2'}"
  filename="${filename//$'7'\$'7'$'7'/$'7'}"

  test -f "$filename" && echo "$myfile exists"

done < text.txt

使用eval

很多人相当合理地看待 eval as a mis-spelling of evil。 因此,我会将此解决方案视为仅在所有其他方法都失败时才使用的最后选择。

我们来看这个示例文件:

$ cat badformat
'new'$'\n''line'
'tab'$'\t''ulator'

我们可以读取和解释这些文件名,如下例所示:

while read -r f; do
    eval "f=$f"; [ -f "$f" ] || echo "file not found"
done <badformat

使用 NUL 分隔的文件名列表

唯一不能出现在 Unix 文件名中的字符是 NUL(十六进制 00)。因此,许多 Unix 工具被设计为能够处理以 NUL 分隔的列表。

因此,在创建文件时,替换:

stat -c %N * >badformat

与:

printf '%s[=13=]' * >safeformat

后一个文件可以通过 while-read 循环读入 shell 脚本。例如:

while IFS= read -r -d $'[=14=]' f; do
    [ -f "$f" ] || echo "file not found"
done <safeformat

除了 shell while-read 循环之外,请注意 grepfindsortxargs 以及 GNU sed 和 GNU awk,都具有处理 NUL 分隔列表的本机能力。因此,NUL 分隔列表方法既安全又得到良好支持。