简体   繁体   English

$(printf'%q'“ $ {@:1}”)是否等于“ $ {*}”?

[英]Is $(printf '%q ' “${@:1}”) equivalent to “${*}”?

Is $(printf '%q ' "${@:1}") equivalent to "${*}" ? $(printf '%q ' "${@:1}")等于"${*}"

If they are, then, doing $(printf '%q ' "${@:2}") (note the 2 instead of 1 as before) is not possible with pure bash $* ? 如果是,那么使用纯bash $*不可能执行$(printf '%q ' "${@:2}") (注意2而不是以前的1)?

Related questions: 相关问题:

  1. POSIX sh equivalent for Bash's printf %q POSIX sh等同于Bash的printf%q
  2. How to use printf "%q " in bash? 如何在bash中使用printf“%q”?
  3. Bash printf %q invalid directive Bash printf%q无效指令
  4. How to make runuser correctly forward all command line arguments, instead of trying to interpret them? 如何使runuser正确转发所有命令行参数,而不是试图解释它们?
  5. How to portability use "${@:2}"? 如何使用“ $ {@:2}”实现可移植性?

No, it is not equivalent, because words are splitted. 不,这不是等效的,因为单词被拆分了。 Ex. 防爆。 the following code: 以下代码:

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}"'"$//'); )

will output: 将输出:

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

tested on repl . repl测试。

The "$*" outputs the arguments delimetered by IFS. "$*"输出由IFS分隔的参数。 So, shown in test 4 , if delimeter is not unset or set to space, then the output of $* will be delimetered by IFS, @ in this example. 因此,如测试4所示,如果未设置delimeter或未将其设置为space,则$*的输出将由IFS(在本示例中为@

Also when IFS is unset or set to space, the output of $* does not include a terminating space, while printf '%q ' will always print a trailing space on the end of the string. 同样,当IFS未设置或设置为空格时, $*的输出不包含终止空格,而printf '%q '将始终在字符串末尾打印尾随空格。

The output of $(printf '%q ' "${@:1}") is still splitted on space. $(printf '%q ' "${@:1}")的输出仍在空间上分割。 So the test case 2 receives 3 arguments, because the space notspace string is separated by space and splitted to two arguments. 因此,测试用例2接收了3个参数,因为space notspace字符串由空格分隔并分成两个参数。 When enclosing the printf inside " will not help - printf substitutes ex. newlines for \\n characters. printf"中将无济于事printf用ex。换行符替换\\n字符。

Cases 5 , 6 , 7 , 8 are my tries to replicate the behavior of "$*" using printf. 5678是我试图复制的行为"$*"用printf。 It can be seen with cases 7 and 8 I used eval , with cases 5 and 6 I quoted the command substitution. 在使用eval情况78可以看到,在情况56我引用了命令替换。 The output of cases ( 5 and 6 ) and ( 7 and 8 ) should match the output of cases 1 and 4 respectively. 案例( 56 )和( 78 )的输出应分别与案例14的输出匹配。

For duplicating the behavior of "$*" special care needs to be taken for IFS to properly delimeter the strings. 为了复制"$*"的行为,需要特别注意IFS以正确地分隔字符串。 I used sed 's/'"${IFS:0:1}"'$//' to remove the trailing IFS separator from the printf output. 我使用sed 's/'"${IFS:0:1}"'$//'printf输出中删除了尾随的IFS分隔符。 The 5 and 6 cases are unquoted $(printf ...) tries, with 6 using IFS=@ to show the separating works. 56情况均未用$(printf ...)引用,其中6使用IFS=@来显示分离效果。 The 7 and 8 cases use eval with special handling on the IFS , cause the IFS character itself needs to be enclosed with quotes, so the shell will not split on it again, that's why printf '%q"'"${IFS:0:1}"'"' . 78情况使用eval对IFS进行特殊处理,导致IFS字符本身需要用引号引起来,因此shell不会在其上再次拆分,这就是为什么printf '%q"'"${IFS:0:1}"'"'

doing $(printf '%q ' "${@:2}") (note the 2 instead of 1 as before) is not possible with pure bash $*? 使用纯bash $ *无法执行$(printf'%q'“ $ {@:2}”)(注意2而不是以前的1)?

You probably could just shift the arguments inside the substitution $(shift; printf "%s\\n" "$*") , but as shown above, they are not equivalent anyway. 您可能只需在替换$(shift; printf "%s\\n" "$*")内移动参数,但是如上所示,它们无论如何都不相等。

Using @Kamil Cuk answer as base, I built this new testing code for illustration, also available on repl : @Kamil Cuk答案为基础,我构建了这个新的测试代码作为示例,也可在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',

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM