$(printf '%q ' "${@:1}")
等于"${*}"
吗?
如果是,那么使用纯bash $(printf '%q ' "${@:2}")
做$*
(注意2代替以前的1)是不可能的吗?
相关问题:
答案 0 :(得分: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或将IFS设置为空格时,$*
的输出不包含终止空格,而printf '%q '
始终在字符串末尾打印尾随空格。
$(printf '%q ' "${@:1}")
的输出仍在空间上分割。因此,测试用例2
接收3个参数,因为space notspace
字符串由空格分隔并分成两个参数。将printf
放在"
内时无济于事-printf
替代ex。 \n
个字符的换行符。
案例5
,6
,7
,8
是我尝试使用printf复制"$*"
的行为。可以看到在我使用7
的情况8
和eval
中,在我引用了命令替换的情况下,在情况5
和6
中可以看到。案例(5
和6
以及(7
和8
的输出应分别与案例1
和4
的输出匹配。
要复制"$*"
的行为,需要特别注意IFS
以正确地分隔字符串。我使用sed 's/'"${IFS:0:1}"'$//'
从printf
输出中删除了尾随的IFS分隔符。 5
和6
案例未引用$(printf ...)
尝试,其中6
使用IFS=@
来展示分离的作品。 7
和8
的情况下,对e IFS
使用eval进行特殊处理,导致IFS
字符本身需要用引号引起来,因此shell不会在其上拆分再次,这就是printf '%q"'"${IFS:0:1}"'"'
的原因。
使用纯bash $ *不可能执行$(printf'%q'“ $ {@:2}”)(注意不是2而是以前的1)?
您可能只需要在替换$(shift; printf "%s\n" "$*")
内移动参数,但是如上所述,它们始终是不相等的。
答案 1 :(得分:0)
使用@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',