[英]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: 相关问题:
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
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. 例
5
, 6
, 7
, 8
是我试图复制的行为"$*"
用printf。 It can be seen with cases 7
and 8
I used eval
, with cases 5
and 6
I quoted the command substitution. 在使用
eval
情况7
和8
可以看到,在情况5
和6
我引用了命令替换。 The output of cases ( 5
and 6
) and ( 7
and 8
) should match the output of cases 1
and 4
respectively. 案例(
5
和6
)和( 7
和8
)的输出应分别与案例1
和4
的输出匹配。
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. 5
和6
情况均未用$(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}"'"'
. 第
7
和8
情况使用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.