【问题标题】:Printing command line arguments in quoted form [duplicate]以引用的形式打印命令行参数[重复]
【发布时间】:2021-12-30 15:28:58
【问题描述】:

$@ 当双引号("$@") 扩展为 "$1" "$2" "$3" ...

似乎没有简单的方法可以打印“$@”中的引用形式

$ set -- "one two" three  
$ echo "$@"
one two three

我正在寻找的是,输出

'one two' three

使用 'set -x' 是否会在 "$@" 中回显带引号的参数形式

$ set -x; echo "$@"; set +x
+ set -x
+ echo 'one two' three
one two three
+ set +x

用户定义的变量 $DOLLAR_AT 里面包含相同的东西,就像 "$@" 包含

$ DOLLAR_AT="'one two' three"

转储 $DOLLAR_AT 里面的内容,使用“echo”按预期工作

$ echo $DOLLAR_AT
'one two' three

由于 shell 对包含特殊字符的参数进行了某种自动引用

$ set -x; echo $DOLLAR_AT; set +x
+ echo ''\''one' 'two'\''' three
+ set +x

不清楚原因

$ echo "$@"

不会产生与

相同的输出
$ echo "$DOLLAR_AT"

当使用接收到的“$@”从 shell 脚本启动命令时,有一个 在调用 命令。

打印输出从 一个 bash 数组。

$ CMDARGS=("one two" "three")

在双引号内计算数组不会以带引号的形式打印数组元素

$ echo "${CMDARGS[@]}"
one two three

我还需要一种紧凑的方式来打印引用的 $CMDARGS[@] 中的内容 类似于本次迭代的形式

$ for ARG in "${CMDARGS[@]}"; do echo \'$ARG\'; done
'one two'
'three'

【问题讨论】:

  • 引号通常被调用您的脚本的(交互式)shell 吃掉。引号的效果(对多字值进行分组)在您的代码运行时已经发挥了作用。值one two 已分配给$1
  • 一般来说,如果你想以转义形式传递值,例如传递/调用另一个脚本时,那么你可以使用printf %q。它自动转义值,以便它们按原样传递到下一个程序。它不使用引号,而只是反斜杠转义空格,这具有相同的最终结果。
  • 需要在 "$@" 或 "${ARRAY[@]}$" 中打印参数,就像在调用它之前传递给被调用脚本一样。
  • @user3477071 但是为什么?考虑printf '%s\n' "$@"。它将在一行打印one two,在下一行打印three。仅仅因为缺少引号并不意味着您没有保留两个参数之间的区别。
  • 您的for 循环已经一次向您显示每个参数;引号没有给你任何额外的信息。

标签: bash shell unix


【解决方案1】:

1。使用参数扩展

你可以试试内联:

$ set -- 'foo bar' baz
$ echo ${@@Q}
'Foo bar' 'baz'

$ echo ${@@A}
set -- 'Foo bar' 'baz'

$ DOLLAR_AT="'one two' three"
$ echo ${DOLLAR_AT@Q}
''\''one two'\'' three'

$ echo ${DOLLAR_AT@A}
DOLLAR_AT=''\''one two'\'' three'

更多信息在 bash 的手册页中,在 Parameter Expansion 小节下。

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

重复使用:

$ myString1=${@@Q}
$ set -- something\ else
$ . <(echo "set -- $myString1")
$ echo ${@@A}
set -- 'Foo bar' 'baz'

1.1。 $*$@ 之间的区别。

$* 用于生成字符串,其中$@ 可以生成数组stringS,具体取决于上下文。

来自 bash 的手册页:

   *      Expands to the positional parameters, starting from  one...
          ...   That  is, "$*" is equivalent to "$1c$2c...", where  c is
          the first character of the value of the IFS variable...
   @      Expands to the positional parameters,  starting  from  one...
          ...  That is, "$@" is equivalent to "$1" "$2" ... 

小演示:

$ paramExpDemo() {
    local IFS=+ _arry
    _arry="${@@Q}"         #  var="..." -> context string
    declare -p _arry

    _arry="${*@Q}"
    declare -p _arry

    _arry=("${@@Q}")       #  var=(...) -> context array
    declare -p _arry

    _arry=("${*@Q}")
    declare -p _arry
}

然后

$ paramExpDemo  'foo bar' baz
declare -- _arry="'foo bar'+'baz'"
declare -- _arry="'foo bar'+'baz'"
declare -a _arry=([0]="'foo bar'" [1]="'baz'")
declare -a _arry=([0]="'foo bar'+'baz'")

在上下文 string 中,$@$* 将给出相同的结果,但在上下文 array 中,$* 将返回 string$@ 返回一个数组。

$ set -- 'foo bar' baz
$ Array=("${@@Q}")
$ declare -p Array
declare -a Array=([0]="'foo bar'" [1]="'baz'")
$ echo "${Array[@]@Q}"
''\''foo bar'\''' ''\''baz'\'''

2。使用printf %q

作为Léa Gris rightly commented out,你可以使用:

$ printf '%q\n' "$@"
Foo\ bar
baz

$ printf -v myString2 "%q " "$@"
$ echo "${myString2% }"
Foo\ bar baz 

重复使用:

$ set -- something\ else
$ . <(echo "set -- $myString2")
$ echo ${@@A}
set -- 'Foo bar' 'baz'

注意:作为Charles Duffy commented out,这并不完美!事实上,没有办法检索在命令行中使用了哪种语法。

$ printf "<%q>\n" "$myString1" "${myString2% }"
<\'Foo\ bar\'\ \'baz\'>
<Foo\\\ bar\ baz>

由于两个字符串都适用于 sourcing 变量,它们并不相同,因此进一步的字符串操作可能会变得复杂...

【讨论】:

  • 还有printf %q\\n "'one two' three"
  • @LéaGris 对,答案已编辑!
  • @user3477071,您说您正在寻找在输入时引用值的确切方式。这并没有给你——它会在输出上打印'one two',即使输入是one\ twoone" "two'one 'two或任何其他写入完全相同的值的方式。 (也就是说,它没有给你的原因是它不可能得到;在所有解析完成后,值作为 C 字符串数组传递,所以输入的详细信息被转换成那个C字符串不见了)
  • @CharlesDuffy :感谢您对输入的警告,这两种方法都将失败。我的脚本收到的“$@”已经是单引号或双引号,如果有任何参数,有任何特殊字符。想要某种方式来查看当“$@”被传递给调用的命令时位置参数是如何分解的。我希望,设置 CMD=" ${@@Q}" 后跟 echo "$CMD" 和 eval "$CMD" 应该可以完成这项工作。
  • 需要明确的是,printf %q${var@Q} 将始终为您提供解析为相同值的内容,即使它的写出方式不同。 所有我给出的例子都是相同的——如果你用someprog one\ twosomeprog one" "two等启动一个C程序,它们都会得到char[][]{"someprog", "one two", NULL}作为它们的argv。但关键是你不能从char[][]{"someprog", "one two", NULL} 回到someprog 'one two',而不是someprog one\ two 或用户使用的任何其他特定调用;该细节只有调用外壳知道
猜你喜欢
  • 1970-01-01
  • 2021-03-12
  • 2016-02-20
  • 1970-01-01
  • 1970-01-01
  • 2023-04-03
  • 2020-05-05
  • 2016-05-01
  • 2020-06-05
相关资源
最近更新 更多