保留bash函数参数中的引号

ezp*_*zpz 23 bash quotes arguments function

我想要做的是,作为函数的输入,可以包括引号(单引号或双引号)和与该函数提供的行完全相同的回声.例如:

function doit {
   printf "%s " ${@} 
   eval "${@}"
   printf " # [%3d]\n" ${?}
}
Run Code Online (Sandbox Code Playgroud)

其中,给出以下输入

doit VAR=42
doit echo 'single quote $VAR'
doit echo "double quote $VAR"
Run Code Online (Sandbox Code Playgroud)

产量如下:

VAR=42  # [  0]
echo single quote $VAR  # [  0]
echo double quote 42  # [  0]
Run Code Online (Sandbox Code Playgroud)

所以变量扩展的语义就像我期望的那样得到保留,但是我无法得到提供给函数的行的确切格式.我想要的是doit echo 'single quote $VAR'结果echo 'single quote $VAR'.

我确信这与bash在传递给函数之前处理参数有关; 我只是想找个方法(如果可能的话).

编辑

所以我的目的是影响脚本的执行,同时提供执行的精确副本,可以用作诊断工具,包括每个步骤的退出状态.

虽然我可以通过做类似的事情获得上述所需的行为

while read line ; do 
   doit ${line}
done < ${INPUT}
Run Code Online (Sandbox Code Playgroud)

面对控制结构(即等)if,这种方法失败了while.我考虑过使用set -x但是也有它的局限性:对于失败的命令,"变为'退出状态并且不可见.

Dav*_*ebb 11

我与你处于类似的位置,因为我需要一个脚本来包装现有命令并传递保持引用的参数.

我想出了一些不完全保存命令行的东西,但确实正确地传递了参数并告诉你它们是什么.

这是我设置为阴影的脚本ls:

CMD=ls
PARAMS=""

for PARAM in "$@"
do
  PARAMS="${PARAMS} \"${PARAM}\""
done

echo Running: ${CMD} ${PARAMS}
bash -c "${CMD} ${PARAMS}"
echo Exit Code: $?
Run Code Online (Sandbox Code Playgroud)

这是一些示例输出:

$ ./shadow.sh missing-file "not a file"
Running: ls "missing-file" "not a file"
ls: missing-file: No such file or directory
ls: not a file: No such file or directory
Exit Code: 1
Run Code Online (Sandbox Code Playgroud)

因此,你可以看到它添加了原来不存在的引号,但它确实保留了带有空格的参数,而这正是我所需要的.

  • 这在肤浅的情况下可能没问题,但你确实需要[使用数组来收集参数](http://mywiki.wooledge.org/BashFAQ/050). (4认同)

Pet*_*ake 7

发生这种情况的原因是因为bash按照您的想法解释了这些参数.当它调用函数时,引号根本不再存在,所以这是不可能的.它在DOS下工作,因为程序可以自己解释命令行,而不是它可以帮助你!


Che*_*evy 5

尽管@Peter Westlake答案是正确的,并且没有引号可以保留,但可以尝试推断引号是否需要并因此最初传入。就个人而言,requote当我需要在我的日志中证明命令以正确的引用运行时,我使用了这个函数:

function requote() {
    local res=""
    for x in "${@}" ; do
        # try to figure out if quoting was required for the $x:
        grep -q "[[:space:]]" <<< "$x" && res="${res} '${x}'" || res="${res} ${x}"
    done
    # remove first space and print:
    sed -e 's/^ //' <<< "${res}"
}
Run Code Online (Sandbox Code Playgroud)

这是我如何使用它:

CMD=$(requote "${@}")
# ...
echo "${CMD}"
Run Code Online (Sandbox Code Playgroud)

  • 更好的是使用 `printf %q`,shell 保证它会生成 `eval` 安全的输出。 (2认同)