printf가 왜 예상보다 많은 인수를 인쇄합니까?


9

이 쉘 스크립트가 입력을 두 번 인쇄하는 이유는 무엇입니까?

스크립트가 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%bprintf %s%\ d%b thing 3 "${var+\cquit printing if set}\nelse do a newline" and 0 keep\ going.
mikeserv

답변:


18

세 가지 문제가 있습니다.

  1. 를 사용하면 read입력의 필드보다 변수 이름이 적 으면 마지막 var는 구분 기호를 사용하여 줄의 나머지 모든 필드에 바인딩됩니다. 즉, 예기치 않은 첫 번째 예 를 $e5 6습니다.
  2. 모든 $a.. $e의 인용 부호가 없기 때문에 값이 필드 분할 됩니다. 경우 $e"보유 5 6"그것은으로 확장 이 개 명령에 대한 인수.
  3. printf%대체 가있을 때 한 번에 많은 인수를 사용하여 반복적으로 모든 인수를 사용 합니다. 이것은 다음 과 같이 설명서에 묻혀 있습니다.

    format피연산자 인수 피연산자를 만족하도록 필요한만큼 자주 재사용한다. 추가 c또는 s변환 지정자는 널 문자열 인수가 제공된 것처럼 평가됩니다. 다른 추가 변환 사양은 0 인수가 제공된 것처럼 평가됩니다.

    즉, 사용하지 않는 인수가 있으면 다시 시작하여 전체 형식 문자열을 포함하여 처음부터 인수를 처리합니다. 이것은 전체 배열을 포맷하고 싶을 때 유용합니다 :

    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가져오고 예상 한 5 개의 인수 만 가져옵니다.


두 번째로 편집 한 질문에는 비슷한 대답 이 있습니다. 공백이 없을 a때만 값을 얻습니다 IFS. 즉 $b.. $e아무것도 확장하지 않으므로 printf단일 인수 만 가져옵니다. 형식 문자열의 공백은 "널 문자열 인수가 제공된 것처럼"공백없이 대체되어 인쇄됩니다.


"$ a"..... "$ e"를 사용하여 두 번째 스크립트를 다시 테스트했습니다. 두 번째 스크립트는 동일한 문제를 다시 발생시킵니다.

3
인용은 두 번째 스크립트와 차이를 만들지 않습니다. 단일 문자열로 a1 2 3 4 5을 가지며 한 번에 대체됩니다.
Michael Homer

6
 printf "> %s < " 1 2 3

인쇄합니다

 > 1 <> 2 <> 3 <

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

인쇄물

 > 1 2 <> 3  <

printf 형식 문자열을 만족시키기 위해 모든 인수를 취한 다음 모든 인수가 처리 될 때까지 반복합니다.

두 번째 스크립트는 오직 $a할당되어 있기 때문에 작동하므로 명령이 추가 반복으로 오버플로되지 않습니다 (한 번의 반복 만 있음).


이 동작은 help printf다음 과 함께 제공되는 텍스트에 설명되어 있습니다 .

... 모든 인수를 사용하기 위해 필요에 따라 형식이 재사용됩니다. 형식에 필요한 인수보다 적은 수의 인수가 있으면 추가 형식 스펙은 0 값 또는 널 문자열이 적절하게 제공된 것처럼 작동합니다. ...

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html 에 의해 의무화됩니다 .


왜 이런 행동입니까? 문서화되어 있습니까?
Shiplu Mokaddim 2011

1
@Shiplu는 행동이 문서화되는 장소와 행동을 요구하는 표준에 관한 단락을 추가했습니다.
PSkocik
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.