如何将文件读入 Bash 中引号数量未知的变量

How do I read a file into a variable with an unknown number of quotes in Bash

我尝试使用 git-bash 将文件读入变量。我正在使用这样的东西:

readFile() {
    local file=""
    local resultVar=""
    eval $resultVar="'$(cat ${file})'"
}

与这里的建议类似 Link

这在大多数情况下都可以正常工作。但它可能会导致问题,具体取决于文件中的引号数量。例如:

例一 ❌

test1.txt:
text "quoted"

code:
$ echo "text \"quoted\"" > test1.txt &&
> readFile "./test1.txt" test1 &&
> printf "test1: %s\n" "${test1}"
test1: text "quoted"

错误:尾随 \n 的剪辑在末尾。

例子2 ❌

test2.txt:
text "one quote

code:
$ echo "text \"one quote" > test2.txt &&
> readFile "./test2.txt" test2 &&
> printf "test2: %s\n" "${test2}"
test2: text "one quote

错误:尾随 \n 的剪辑在末尾。

例3 ❌

test3.txt:
text 'quoted'

code:
$ echo "text 'quoted'" > test3.txt &&
> readFile "./test3.txt" test3 &&
> printf "test3: %s\n" "${test3}"
test3: text quoted

错误:这些single-quotes已被删除!

范例 4 ❌

test4.txt:
text 'one quote

code:
$ echo "text 'one quote" > test4.txt &&
> readFile "./test4.txt" test4 &&
> printf "test4: %s\n" "${test4}"
bash: unexpected EOF while looking for matching `''
bash: syntax error: unexpected end of file

错误:这变得更糟了...

范例 5 ❌

test5.txt:
text 'quoted"

code:
$ echo "text \'quoted\"" > test5.txt &&
> readFile "./test5.txt" test5 &&
> printf "test5: %s\n" "${test5}"
bash: unexpected EOF while looking for matching `"'
bash: syntax error: unexpected end of file

ERROR: 同上。


那么,我如何在不知道它是否包含引号、包含多少引号以及包含何种类型的引号的情况下,将函数中的文件稳健地读取到变量中?

也许还有其他字符也可以破坏我的代码,但我没有检查。如果解决方案也能解决这些问题,那就太好了。

不要使用 eval。

bash 中,您可以 $(<file) 而不是 $(cat file)。只是快了一点。

您可以使用名称参考:

readFile() {
    declare -n resultVar=
    resultVar="$(<"")"
}

如果没有零字节,您可以使用readarray/mapfile。注意 - 它将保留尾随换行符,而不是 $(...) 删除尾随换行符:

readFile() {
    readarray -d '' -t "" < ""
}

如果你真的想用eval,那就用declare:

readFile() {
    declare -g "=$(< "")"
}

如果您真的很想使用 eval,请始终将正确转义的字符串传递给它,即。总是在 printf "%q":

之后
readFile() {
    eval "$(printf "%q" "")=$(printf "%q" "$(< "")")"
}

这样可以实现你想要的吗?

#!/usr/bin/env bash
  
readFile() {
    IFS= read -rd '' "" < ""
}   

readFile var data-file

# Checking result
printf %s "$var" | xxd