在bash参数中保留引号

时间:2012-05-31 14:48:21

标签: linux bash

我正在制作一个bash脚本,它将打印并将复杂的参数传递给另一个外部程序。

./script -m root@hostname,root@hostname -o -q -- 'uptime ; uname -a'

如何打印原始参数:

-m root@hostname,root@hostname -o -q -- 'uptime ; uname -a'

使用$@$*删除uptime ; uname -a周围的单引号,这可能会导致意外结果。我的脚本不需要解析每个参数。我只需要打印/记录参数字符串并将它们传递给另一个程序,确切地说它们是如何给出的。

我知道我可以使用类似"'uptime ; uname -a'"的内容来逃避引号,但我无法保证用户会这样做。

7 个答案:

答案 0 :(得分:14)

在将参数传递给脚本之前删除了引号,因此保留它们为时已晚。你可以做的是在将参数传递给内部命令时保留它们的效果,并重建用于打印的参数的等效引用/转义版本。

为了将参数传递给内部命令"$@" - 使用双引号,$ @保留原始单词分隔符,这意味着内部命令接收与脚本完全相同的参数列表。

对于打印,您可以在bash的printf命令中使用%q格式来重建引用。请注意,这并不总是重建原始引用,但会构造一个等效的引用/转义字符串。例如,如果您传递参数'uptime ; uname -a',则可能会打印uptime\ \;\ uname\ -a"uptime ; uname -a"或任何其他等效项(请参阅@William Pursell对类似示例的回答)。

以下是使用这些的示例:

printf "Running command:"
printf " %q" innercmd "$@" # note the space before %q -- this inserts spaces between arguments
printf "\n"
innercmd "$@"

答案 1 :(得分:4)

如果要打印参数列表尽可能接近用户可能输入的内容:

#!/bin/bash
chars='[ !"#$&()*,;<>?\^`{|}]'
for arg
do
    if [[ $arg == *\'* ]]
    then
        arg=\""$arg"\"
    elif [[ $arg == *$chars* ]]
    then
        arg="'$arg'"
    fi
    allargs+=("$arg")    # ${allargs[@]} is to be used only for printing
done
printf '%s\n' "${allargs[*]}"

这不完美。像''\''"'这样的论点比合理的更难以容纳。

答案 2 :(得分:3)

如果用户调用您的命令:

./script 'foo'

给脚本的第一个参数是不带引号的字符串foo。您的脚本无法区分该脚本以及可以将foo作为参数的任何其他方法(例如./script $(echo foo)./script foo./script "foo"./script \f\o""''""o)。

答案 3 :(得分:1)

正如其他人已经提到的那样,当您访问脚本内部的参数时,现在知道调用哪些参数被引用为时已晚。但是,您可以重新引用包含空格或其他特殊字符的参数,这些参数需要引号作为参数传递。

这是一个基于Python's shlex.quote(s)的Bash实现,它执行以下操作:

function quote() {
  declare -a params
  for param; do
    if [[ -z "${param}" || "${param}" =~ [^A-Za-z0-9_@%+=:,./-] ]]; then
      params+=("'${param//\'/\'\"\'\"\'}'")
    else
      params+=("${param}")
    fi
  done
  echo "${params[*]}"
}

您的示例略有更改,以显示空参数:

$ quote -m root@hostname,root@hostname -o -q -- 'uptime ; uname -a' ''
-m root@hostname,root@hostname -o -q -- 'uptime ; uname -a' ''

答案 4 :(得分:0)

eval "./script -m root@hostname,root@hostname -o -q -- 'uptime ; uname -a'"

https://ss64.com/bash/eval.html

答案 5 :(得分:-1)

使用$ {@@ Q}作为简单的解决方案。要进行测试,请在脚本bigQ中放置以下行。

    CngKey key;
    bool keyExists = CngKey.Exists(KEY_NAME);
    if (!keyExists)
    {
        CngKeyCreationParameters parameters = new CngKeyCreationParameters()
        {
            ExportPolicy = CngExportPolicies.AllowPlaintextExport,
            Provider = CngProvider.MicrosoftSoftwareKeyStorageProvider,
            KeyUsage = CngKeyUsages.AllUsages
        };
        CngProperty property = new CngProperty("Length", BitConverter.GetBytes(RSA_KEY_SIZE), CngPropertyOptions.None);
        parameters.Parameters.Add(property);

key = CngKey.Create(CngAlgorithm.Rsa, KEY_NAME, parameters);

}

答案 6 :(得分:-1)


?️ 保持分离

不需要保留引号,而只需要保留参数分隔。

对于传递参数为:"${@}"


?️ 函数返回

如果您需要从函数返回参数,请使用 for 循环

for arg in "${args[@]}"; do
    echo "${arg}"
done

并在接收器中重建为数组

readarray -t args < <(function "${@}")

? 引用

如果这还不够,将每个单独的论点引用为:"${@@Q}"