有人可以解释为什么此输出拆分到新行吗?
$ cat ./test-args.sh
#!/usr/bin/env bash
while [[ $# -gt 0 ]]; do
printf '%b %b %b %b\n' "$0" "$1" "$#" "$@"
shift
done
$ ./test-args.sh a b c d e
./test-args.sh a 5 a
b c d e
./test-args.sh b 4 b
c d e
./test-args.sh c 3 c
d e
./test-args.sh d 2 d
e
./test-args.sh e 1 e
将特殊参数分配给变量可以按预期工作:
$ cat ./test-args.sh
#!/usr/bin/env bash
while [[ $# -gt 0 ]]; do
a=$0
b=$1
c=$#
d=$@
printf '%b %b %b %b\n' "$a" "$b" "$c" "$d"
shift
done
$ ./test-args.sh a b c d e
./test-args.sh a 5 a b c d e
./test-args.sh b 4 b c d e
./test-args.sh c 3 c d e
./test-args.sh d 2 d e
./test-args.sh e 1 e
答案 0 :(得分:4)
printf
收到额外的参数时,它将在额外的单词上重复格式字符串。例如:
$ printf '[%s]\n' a b c
[a]
[b]
[c]
您的printf
格式字符串需要四个参数,但是"$@"
扩展为多个单词。它在格式字符串上运行了两次,这就是\n
在“中间”显示的原因。如果将格式字符串更改为'<%b %b %b %b>\n'
,则会很清楚:
$ ./test-args.sh a b c d e
<./test-args.sh a 5 a>
<b c d e>
<./test-args.sh b 4 b>
<c d e >
<./test-args.sh c 3 c>
<d e >
<./test-args.sh d 2 d>
<e >
<./test-args.sh e 1 e>
您可以通过将"$@"
更改为"$*"
来解决此问题,以便所有参数都作为单个字符串传递。
为什么分配变量会改变行为?这是因为d=$@
不能保留$@
的“排列性”。像$*
一样,它将参数连接成一个字符串。要获得数组行为,您需要编写:
a=$0
b=$1
c=$#
d=("$@")
printf '%b %b %b %b\n' "$a" "$b" "$c" "${d[@]}"
答案 1 :(得分:1)
如果为printf
提供的属性超出其格式使用的属性,它将重新使用其格式。在您的情况下,"$@"
扩展为用双引号引起来的所有参数,(在第一种情况下,"a" "b" "c" "d" "e"
),并且printf
收到8个参数,并使用两次出现的格式字符串来显示,提供您意想不到的输出。
为避免此行为,您将需要使用"$*"
,它将扩展为单个参数,在第一种情况下为"a b c d e"
。
答案 2 :(得分:0)
想法是,printf遍历参数。因此,在第一个循环中
printf '%b %b %b %b\n' "$0" "$1" "$#" "$@"
扩展到
printf '%b %b %b %b\n' ./test-args.sh a 5 a b c d e
printf接受前四个参数./test-args.sh a 5 a
并使用%b %b %b %b\n
打印它们。然后,它需要另外4个(或更少)自变量b c d e
并再次使用%b %b %b %b\n
来打印它们。基本上printf '%b %b %b %b\n' ./test-args.sh a 5 a b c d e
与
printf '%b %b %b %b\n' ./test-args.sh a 5 a b
printf '%b %b %b %b\n' b c d e
因此它打印多行。
这将满足您的要求:
while (($#)); do
printf '%s ' "$0" "$1" "$#" "$@"
printf '\n'
shift
done
或者也许:
while (($#)); do
printf '%s %s %s %s\n' "$0" "$1" "$#" "$*"
shift
done