단순히 에코 대 printf가 아닙니다.
먼저, read a b c
부분 이 어떻게되는지 이해합시다 . space-tab-newline read
인 IFS
variable 의 기본값을 기반으로 단어 분할을 수행 하고 그에 따라 모든 것을 맞출 것입니다. 보유 할 변수보다 더 많은 입력이 있으면 분할 된 부분을 첫 번째 변수에 맞추고 적합하지 않은 것은 마지막에갑니다. 여기 내가 의미하는 바가있다 :
bash-4.3$ read a b c <<< "one two three four"
bash-4.3$ echo $a
one
bash-4.3$ echo $b
two
bash-4.3$ echo $c
three four
이것은 bash
설명서에 설명 된 것과 정확히 같습니다 (응답 끝의 인용문 참조).
귀하의 경우 1과 2는 a와 b 변수에 적합하고 c는 다른 모든 것을 취 3 4 5 6
합니다.
또한 여러 번 보게 될 것은 사람들이 while IFS= read -r line; do ... ; done < input.txt
텍스트 파일을 한 줄씩 읽는 데 사용한다는 것 입니다. 다시 말하지만, IFS=
단어 분할을 제어하거나 더 구체적으로-단어를 비활성화하고 한 줄의 텍스트를 변수로 읽는 이유입니다. 존재하지 않는다면 read
각 개별 단어를 line
변수 에 맞추려고 합니다. 그러나 그것은 또 다른 이야기 while IFS= read -r variable
입니다. 매우 자주 사용되는 구조 이기 때문에 나중에 공부하도록 권장합니다 .
에코 대 printf 동작
echo
당신이 여기서 기대하는 것을 수행합니다. 변수 read
를 정렬 한 그대로 표시합니다 . 이것은 이미 이전 토론에서 입증되었습니다.
printf
변수가 모두 소진 될 때까지 형식 문자열에 변수를 계속 맞추기 때문에 매우 특별합니다. 따라서 printf "%d, %d, %d \n" $a $b $c
printf를 사용 하면 소수점 이하 3 자의 형식 문자열이 표시되지만 3보다 많은 인수가 있습니다 (변수가 실제로 개별 1,2,3,4,5,6으로 확장되기 때문입니다). 혼동되는 것처럼 들릴 수 있지만 C 언어에서 실제 printf()
기능이 수행 하는 동작의 개선 된 동작으로 인해 존재 합니다.
출력에 영향을 미치는 여기서 수행 한 작업은 변수가 따옴표로 묶여 있지 않으므로 쉘 ( printf
)이 변수를 6 개의 개별 항목으로 나눌 수 있습니다. 이것을 따옴표와 비교하십시오.
bash-4.3$ read a b c <<< "1 2 3 4"
bash-4.3$ printf "%d %d %d\n" "$a" "$b" "$c"
bash: printf: 3 4: invalid number
1 2 3
정확히 $c
변수가 따옴표로 묶여 있기 때문에 이제는 하나의 전체 문자열로 인식되며 형식에 3 4
맞지 않습니다 ( %d
단일 정수).
이제 인용하지 않고 똑같이하십시오 :
bash-4.3$ printf "%d %d %d\n" $a $b $c
1 2 3
4 0 0
printf
다시 말하길 : "여러분은 6 개의 아이템을 가지고 있지만 포맷은 단지 3을 보여 주므로, 사용자의 실제 입력에 맞지 않는 것을 맞추고 비워 둘 것입니다".
그리고이 모든 경우에 당신은 그것에 대해 내 말을 할 필요가 없습니다. 그냥 실행 strace -e trace=execve
하고 명령이 실제로 "을 참조하십시오"무엇을 직접 볼 :
bash-4.3$ strace -e trace=execve printf "%d %d %d\n" $a $b $c
execve("/usr/bin/printf", ["printf", "%d %d %d\\n", "1", "2", "3", "4"], [/* 80 vars */]) = 0
1 2 3
4 0 0
+++ exited with 0 +++
bash-4.3$ strace -e trace=execve printf "%d %d %d\n" "$a" "$b" "$c"
execve("/usr/bin/printf", ["printf", "%d %d %d\\n", "1", "2", "3 4"], [/* 80 vars */]) = 0
1 2 printf: ‘3 4’: value not completely converted
3
+++ exited with 1 +++
추가 사항
Charles Duffy가 주석에서 올바르게 지적했듯이 명령에 사용하는 bash
자체 내장 기능이 있으며 실제로는 쉘 버전이 아닌 버전을 호출 합니다. 사소한 차이점을 제외하고이 특정 질문에 대한 우리의 관심을 끌기 위해 표준 형식 지정자는 동일하고 동작은 동일합니다.printf
strace
/usr/bin/printf
명심해야 할 것은 printf
구문이 echo
C 또는 C와 유사한 언어에 익숙하다는 점은 말할 것도없이 구문이 이식성이 뛰어 나기 때문에 선호 된다는 printf()
것입니다. vs 의 주제에 대해 terdon 이 훌륭한 답변을 참조하십시오 . 특정 버전의 Ubuntu에서 특정 셸에 맞게 출력을 조정할 수 있지만 다른 시스템에 스크립트를 이식하려는 경우 echo보다는 선호하는 것이 좋습니다. Ubuntu 및 CentOS 시스템을 사용하는 초보자 시스템 관리자이거나 FreeBSD (아는 사람도 있음) 일 수도 있으므로 그러한 경우에는 선택해야합니다.printf
echo
printf
bash 매뉴얼, SHELL BUILTIN COMMANDS 섹션에서 인용
[-ers] [-a aname] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ... ]
한 줄은 표준 입력 또는 -u 옵션에 대한 인수로 제공된 파일 디스크립터 fd에서 읽히고 첫 번째 단어는 첫 번째 이름에 지정되고 두 번째 단어는 두 번째 이름에 지정됩니다. 성에 지정된 단어와 그 중간 분리 자. 입력 스트림에서 읽은 단어가 이름보다 적은 경우 나머지 이름에는 빈 값이 할당됩니다. IFS의 문자는 쉘이 확장에 사용하는 것과 동일한 규칙을 사용하여 행을 단어로 분할하는 데 사용됩니다 (위의 단어 분할에서 설명).
strace
대소 문자와 대소 문자 사이의 주목할만한 차이점 중 하나strace printf
는을 사용/usr/bin/printf
하는 반면printf
bash에서 직접 동일한 이름으로 내장 된 쉘을 사용하는 것입니다. 예를 들어, bash 인스턴스에는 형식 지정자%q
와 새 버전에서$()T
시간 형식 지정이 항상 같은 것은 아닙니다 .