为什么printf会输出比预期更多的参数?


9

为什么此shell脚本打印两次输入?

我希望脚本在5之后会忽略输入。

脚本:

#! /bin/bash
echo "Enter 5 words : "
read  a b c d e 
printf "> %s %s %s %s %s <" $a $b $c $d $e

输出:

user@linux:~$ pico ifs2.sh
user@linux:~$ ./ifs2.sh
Enter 5 words : 
1 2 3 4 5 
> 1 2 3 4 5 <user@linux:~$ ./ifs2.sh
Enter 5 words : 
1 2 3 4 5 6
> 1 2 3 4 5 <> 6     <user@linux:~$ ./ifs2.sh
Enter 5 words : 
1 2 3 4 5 6 7 8 9 0
> 1 2 3 4 5 <> 6 7 8 9 0 <user@linux:~$ 

而且,无论将$ IFS设置为什么,以下脚本都可以工作。为什么?

#! /bin/bash    
old="$IFS"
IFS=":"
echo "IFS = $IFS"
echo "Enter 5 words : "
read  a b c d e 
printf "> %s %s %s %s %s <" $a $b $c $d $e    
IFS="$old"

输出:

user@linux:~$ ./ifs2.sh
IFS = :
Enter 5 words : 
1 2 3 4 5  
> 1 2 3 4 5      <user@linux:~$ ./ifs2.sh
IFS = :
Enter 5 words : 
1 2 3 4 5
> 1 2 3 4 5     <user@linux:~$ ./ifs2.sh
IFS = :
Enter 5 words : 
1:2:3:4:5
> 1 2 3 4 5 <user@linux:~$ 

printf随时停止\c%b格式说明符关联的转义符。喜欢:printf %s%\ d%b thing 3 "${var+\cquit printing if set}\nelse do a newline" and 0 keep\ going.
mikeserv

Answers:


18

您有三个问题:

  1. 使用read,如果变量名少于输入中的字段,则最后一个var将使用定界符绑定到行上所有其余字段。这意味着,$e获得5 6你的第一个意想不到的例子。
  2. 由于所有$a.. $e都未加引号,因此它们的值会进行字段分割。如果$e持有“ 5 6”,则它将扩展为命令的两个参数。
  3. printf消耗所有的参数,一次使用多达%替换的参数,反复使用。这是埋在文档中为:

    format为了满足自变量操作数,应尽可能重复使用该操作数。评估任何额外的cs转换的说明符,就好像提供了空字符串参数一样;应评估其他额外的转换规范,就像提供了零自变量一样。

    换句话说,如果有未使用的参数,它将重新开始并也从头开始处理它们,包括整个格式字符串。当您要格式化整个数组时,这很有用:

    printf '%b ' "${array[@]}"

    您的printf命令从$a..的每个参数中获取一个参数$d,然后从中遗留下许多参数$e。当$e为“ 5 6”时,printf有两次处理,第二次才6格式化。当它5 6 7 8 9 10具有第二次打印的全部替代范围时。


您可以通过在上添加一个额外的虚拟字段read并引用参数替换来避免所有这些情况(这总是一个好主意):

read  a b c d e dummy
printf "> %s %s %s %s %s <" "$a" "$b" "$c" "$d" "$e"

这将给出:

Enter 5 words : 
1 2 3 4 5 6 7 8 9 10
> 1 2 3 4 5 <

dummy获取所有额外的字段,并且printf仅获取您期望的五个参数。


您的第二个编辑问题有一个相似的答案:只有aIFS没有空格的情况下才能获取值。这意味着$b.. $e扩展为空,因此printf只得到一个参数。将打印格式字符串中的空格,并且空格之间不会替换任何空格(“就像提供了空字符串参数一样”)。


我再次使用“ $ a” .....“ $ e”测试了第二个脚本。第二个脚本再次出现相同的问题。

3
引用不会对第二个脚本产生影响。a具有1 2 3 4 5作为单个字符串的值,并且它立即被全部替换。
Michael Homer 2015年

6
 printf "> %s < " 1 2 3

将打印

 > 1 <> 2 <> 3 <

  printf "> %s %s <" 1 2 3

版画

 > 1 2 <> 3  <

printf 吃掉所有参数以满足其格式字符串,然后重复执行,直到处理完所有参数为止。

第二个脚本之所以有效,$a是因为仅分配了该脚本,因此该命令不会溢出到其他迭代中(只有一个迭代)。


此行为记录在随附的文本中help printf

...根据需要重新使用格式以使用所有参数。如果参数的数量少于格式要求的数量,则额外的格式规范将表现为提供了零值或空字符串(视情况而定)。...

并且由http://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html授权


为什么会这样?有文件记录吗?
Shiplu Mokaddim

1
@Shiplu添加了一段有关行为记录的地方以及要求该行为的标准的段落。
PSkocik 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.