【问题标题】:Is $(printf '%q ' "${@:1}") equivalent to "${*}"?$(printf '%q ' "${@:1}") 是否等同于 "${*}"?
【发布时间】:2019-11-11 05:00:38
【问题描述】:

$(printf '%q ' "${@:1}") 是否等同于 "${*}"

如果它们是,那么,用纯 bash $*$(printf '%q ' "${@:2}")(注意 2 而不是 1)是不可能的?

相关问题:

  1. POSIX sh equivalent for Bash’s printf %q
  2. How to use printf "%q " in bash?
  3. Bash printf %q invalid directive
  4. How to make runuser correctly forward all command line arguments, instead of trying to interpret them?
  5. How to portability use "${@:2}"?

【问题讨论】:

  • 你为什么不试试看呢?
  • 使用"${*}"(通常写成"$*")会产生一个字符串。 POSIX 没有为printf 命令或printf() 函数指定%q 转换规范。您必须参考您的系统的文档才能知道要执行的操作。

标签: bash shell arguments parameter-passing posix


【解决方案1】:

不,它不等价,因为单词是分开的。前任。以下代码:

check_args() {
  echo "\$#=$#"
  printf "%s\n" "$@";
}

# setting arguments
set -- "space notspace" "newline"$'\n'"newline"
echo '1: ---------------- "$*"'
check_args "$*"

echo '2: ---------------- $(printf '\''%q '\'' "${@:1}")'
check_args $(printf '%q ' "${@:1}")

echo '3: ---------------- "$(printf '\''%q '\'' "${@:1}")"'
check_args "$(printf '%q ' "${@:1}")"

echo '4: ---------------- IFS=@ and "$*"'
( IFS=@; check_args "$*"; )

echo "5: ---------------- duplicating quoted"
check_args "$(printf '%s'"${IFS:0:1}" "${@:1}" | sed 's/'"${IFS:0:1}"'$//')"

echo "6: ---------------- duplicating quoted IFS=@"
( IFS=@; check_args "$(printf '%s'"${IFS:0:1}" "${@:1}" | sed 's/'"${IFS:0:1}"'$//')"; )

echo "7: ---------------- duplicating eval unquoted"
eval check_args $(printf '%q"'"${IFS:0:1}"'"' "${@:1}" | sed 's/'"${IFS:0:1}"'$//')

echo "8: ---------------- duplicating eval unquoted IFS=@"
( eval check_args $(IFS=@ ; printf '%q"'"${IFS:0:1}"'"' "${@:1}" | sed 's/"'"${IFS:0:1}"'"$//'); )

将输出:

1: ---------------- "$*"
$#=1
space notspace newline
newline
2: ---------------- $(printf '%q ' "${@:1}")
$#=3
space\
notspace
$'newline\nnewline'
3: ---------------- "$(printf '%q ' "${@:1}")"
$#=1
space\ notspace $'newline\nnewline'
4: ---------------- IFS=@ and "$*"
$#=1
space notspace@newline
newline
5: ---------------- duplicating quoted
$#=1
space notspace newline
newline
6: ---------------- duplicating quoted IFS=@
$#=1
space notspace@newline
newline
7: ---------------- duplicating eval unquoted
$#=1
space notspace newline
newline
8: ---------------- duplicating eval unquoted IFS=@
$#=1
space notspace@newline
newline

repl 上测试。

"$*" 输出由 IFS 分隔的参数。因此,在测试4 中显示,如果分隔符没有取消设置或设置为空格,则$* 的输出将由 IFS 分隔,在此示例中为@

此外,当 IFS 未设置或设置为空格时,$* 的输出不包括终止空格,而printf '%q ' 将始终在字符串末尾打印尾随空格。

$(printf '%q ' "${@:1}") 的输出仍然在空间上分割。所以测试用例2 接收3 ​​个参数,因为space notspace 字符串由空格分隔并拆分为两个参数。当将printf 包含在" 内时,printf 将替代 ex。 \n 字符的换行符。

案例5678 是我尝试使用 printf 复制 "$*" 的行为。在78 的情况下可以看出,我使用了eval,在56 的情况下我引用了命令替换。案例(56)和(78)的输出应分别与案例 14 的输出匹配。

为了复制"$*" 的行为,需要特别注意IFS 以正确分隔字符串。我使用sed 's/'"${IFS:0:1}"'$//'printf 输出中删除尾随的IFS 分隔符。 56 案例未引用 $(printf ...) 尝试,6 使用 IFS=@ 显示分离作品。 78 使用 eval 对 IFS 进行特殊处理,导致 IFS 字符本身需要用引号括起来,因此 shell 不会再次对其进行拆分,这就是 printf '%q"'"${IFS:0:1}"'"' 的原因。

用纯 bash $* 做 $(printf '%q ' "${@:2}") (注意 2 而不是 1 )是不可能的?

您可能只需在替换 $(shift; printf "%s\n" "$*") 中移动参数,但如上所示,它们无论如何都不等价。

【讨论】:

    【解决方案2】:

    使用@Kamil Cuk 的答案作为基础,我构建了这个新的测试代码用于说明,还有available on repl

    #!/bin/bash
    check_args() {
      echo "\$#=$#"
      local counter=0
      for var in "$@"
      do
          counter=$((counter+1));
          printf "$counter. '$var', ";
      done
      printf "\\n\\n"
    }
    
    # setting arguments
    set -- "space notspace" "lastargument"; counter=1
    echo $counter': ---------------- "$*"'; counter=$((counter+1))
    check_args "$*"
    
    echo $counter': ---------------- $*'; counter=$((counter+1))
    check_args $*
    
    echo $counter': ---------------- "$@"'; counter=$((counter+1))
    check_args "$@"
    
    echo $counter': ---------------- $@'; counter=$((counter+1))
    check_args $@
    
    echo $counter': ---------------- $(printf '\''%q '\'' "${@:1}")'; counter=$((counter+1))
    check_args $(printf '%q ' "${@:1}")
    
    echo $counter': ---------------- "$(printf '\''%q '\'' "${@:1}")"'; counter=$((counter+1))
    check_args "$(printf '%q ' "${@:1}")"
    
    echo $counter': ---------------- IFS=@ and "$*"'; counter=$((counter+1))
    ( IFS=@; check_args "$*"; )
    
    echo "$counter: ---------------- duplicating quoted"; counter=$((counter+1))
    check_args "$(printf '%s'"${IFS:0:1}" "${@:1}" | sed 's/'"${IFS:0:1}"'$//')"
    
    echo "$counter: ---------------- duplicating quoted IFS=@"; counter=$((counter+1))
    ( IFS=@; check_args "$(printf '%s'"${IFS:0:1}" "${@:1}" | sed 's/'"${IFS:0:1}"'$//')"; )
    
    echo "$counter: ---------------- duplicating eval unquoted"; counter=$((counter+1))
    eval check_args $(printf '%q"'"${IFS:0:1}"'"' "${@:1}" | sed 's/'"${IFS:0:1}"'$//')
    
    echo "$counter: ---------------- duplicating eval unquoted IFS=@"; counter=$((counter+1))
    ( eval check_args $(IFS=@ ; printf '%q"'"${IFS:0:1}"'"' "${@:1}" | sed 's/"'"${IFS:0:1}"'"$//'); )
    

    -->

    GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)
    1: ---------------- "$*"
    $#=1
    1. 'space notspace lastargument',
    
    2: ---------------- $*
    $#=3
    1. 'space', 2. 'notspace', 3. 'lastargument',
    
    3: ---------------- "$@"
    $#=2
    1. 'space notspace', 2. 'lastargument',
    
    4: ---------------- $@
    $#=3
    1. 'space', 2. 'notspace', 3. 'lastargument',
    
    5: ---------------- $(printf '%q ' "${@:1}")
    $#=3
    1. 'space', 2. 'notspace', 3. 'lastargument',
    
    6: ---------------- "$(printf '%q ' "${@:1}")"
    $#=1
    1. 'space\ notspace lastargument ',
    
    7: ---------------- IFS=@ and "$*"
    $#=1
    1. 'space notspace@lastargument',
    
    8: ---------------- duplicating quoted
    $#=1
    1. 'space notspace lastargument',
    
    9: ---------------- duplicating quoted IFS=@
    $#=1
    1. 'space notspace@lastargument',
    
    10: ---------------- duplicating eval unquoted
    $#=1
    1. 'space notspace lastargument ',
    
    11: ---------------- duplicating eval unquoted IFS=@
    $#=1
    1. 'space notspace@lastargument',
    

    【讨论】:

      猜你喜欢
      • 2022-01-06
      • 1970-01-01
      • 1970-01-01
      • 2012-08-23
      • 1970-01-01
      • 2019-12-23
      • 2013-07-22
      • 1970-01-01
      • 2018-09-01
      相关资源
      最近更新 更多