printf
printf [-v var] format [arguments]
printf 에서는 기본적으로 " "
, ' '
모두에서 escape 문자가 처리됩니다.
escape 문자가 처리되지 않게 하려면 따로 %s
format 을 사용합니다.
echo 명령의 경우 sh
과 bash
가 escape 문자를 처리하는 방식이 다른데 printf 는 그런 차이가 없습니다.
quotes 의 고유 기능은 그대로 유지 되므로 " "
에서는 변수확장, 명령치환 이 됩니다.
$ AA=world
# double quotes
$ printf "hello\t$AA\n" # \t \n escape 문자가 처리되고 변수확장이 된다.
hello world
# single quotes
$ printf 'hello\t$AA\n' # \t \n escape 문자만 처리된다.
hello $AA
16 진수, 8 진수로 문자를 출력할때는 printf "%c" ... 형식으로 하지않습니다.
$ printf "hello \x41\x42\x43\n" # 16 진수
hello ABC
$ printf "hello \101\102\103\n" # 8 진수
hello ABC
-v var
옵션은 출력값을 변수에 저장합니다. (bash only)
$ printf -v IFS " \t\n"
Arguments
printf 는 format tags 와 그에 상응하는 인수를 이용하여 여러가지 형태로 출력할 수 있습니다. 이때 인수에 사용되는 숫자는 다음과 같은 형식을 사용할 수 있습니다.
N
: 10 진수 (decimal) 숫자0N
: 8 진수 (octal) 숫자0xN
: 16 진수 (hexadecimal) 소문자 숫자0XN
: 16 진수 (hexadecimal) 대문자 숫자'X
: X 는 a character"X
: X 는 a character
# %d 는 인수 값을 10 진수로 표시
$ printf "%d\n" 10 # decimal
10
$ printf "%d\n" 010 # octal
8
$ printf "%d\n" 0x10 # hexadecimal
16
$ printf "%d\n" "'A" # a character
65
format tags 개수보다 인수의 개수가 많을 경우는 명령이 반복됩니다.
$ printf "< %d >" 11
< 11 >
$ printf "< %d >" 11 22 33 # %d 는 하나인데 인수는 3개 이므로 3번 반복
< 11 >< 22 >< 33 >
$ printf "< %d >\n" 11
< 11 >
$ printf "< %d >\n" 11 22 33
< 11 >
< 22 >
< 33 >
$ args() {
echo COUNT: $#
printf "ARG: %s\n" "$@"
}
$ args 11 22 33
COUNT: 3
ARG: 11
ARG: 22
ARG: 33
Format Tags
format 스트링에서 다음과 같이 format tag 을 구성하여 인수 값의 출력 형태를 변경할 수 있습니다.
%[flags][width][.precision]specifier
Specifier
%d, %i
: signed decimal number 로 표시합니다.%u
: unsigned decimal number 로 표시합니다.%o
: unsigned octal number 로 표시합니다.%x
: unsigned hexadecimal number (소문자) 로 표시합니다.%X
: %x 와 같으나 대문자로 표시합니다.
$ printf "%d, %d\n" 10 -10 # signed decimal
10, -10
$ printf "%u, %u\n" 10 -10 # unsigned decimal
10, 18446744073709551606
$ printf "%o, %o\n" 10 -10 # unsigned octal
12, 1777777777777777777766
$ printf "%x, %x\n" 10 -10 # unsigned hexadecimal
a, fffffffffffffff6
%f
: floating point number 로 표시합니다.%e
: scientific notation 으로 표시합니다.%E
: %e 와 같으나 대문자 E 를 사용합니다.%g
: 값에 따라 floating point number 또는 scientific notation 을 사용합니다.%G
: %g 와 같으나 scientific notation 에서 대문자 E 를 사용합니다.%a
: C99 형식의 hexadecimal floating point number 로 표시합니다. ( bash only )%A
: %a 와 같으나 대문자로 표시합니다. ( bash only )
$ printf "%e\n" 123 # scientific notation
1.230000e+02
$ printf "%f\n" 123 # floating point number
123.000000
$ printf "%g\n" 123
123
$ printf "%f\n" 123.4567
123.456700
$ printf "%g\n" 123.4567 # floating point number
123.457
$ printf "%f\n" 12345678.123
12345678.123000
$ printf "%g\n" 12345678.123 # scientific notation
1.23457e+07
$ printf "%f\n" 0.0000123
0.000012
$ printf "%g\n" 0.0000123 # scientific notation
1.23e-05
$ printf "%a\n" 123.4567 # hexadecimal floating point number
0xf.6e9d495182a9931p+3
%s
: 인수 값을 escape 문자 처리 없이 그대로 출력합니다.%b
: 인수 값을 escape 문자 처리하여 출력합니다.
$ printf "%s\n" 'hello\tworld'
hello\tworld # escape 문자 처리 없이 그대로 출력
$ printf "%b\n" 'hello\tworld'
hello world # escape 문자를 처리하여 출력
%q
: shell 의 input 으로 사용할수 있게 escape 하여 출력합니다.
# 'bash -c CMD' 에서 실행하고자 하는 명령이 제대로 전달되지 않는다.
$ echo 'echo -e "first\nsecond"' | xargs -I CMD bash -c CMD
firstnsecond # \n 처리가 되지 않는다.
$ printf "%q\n" 'echo -e "first\nsecond"'
# echo\ -e\ \"first\\nsecond\"
$ printf "%q\n" 'echo -e "first\nsecond"' | xargs -I CMD bash -c CMD
first
second
-----------------------------------------------------------------
$ cat commands.txt
echo -e "first\nsecond"
echo -e "third\nfourth"
echo -e "fifth\nsixth"
$ cat commands.txt |
while read -r CMD; do printf "%q\n" "$CMD"; done |
xargs --max-procs=3 -I CMD bash -c CMD
----------------------------------------------------------------
# 공백이 있는 파일이름을 touch 명령의 인수로 올바르게 전달하기 위해
sshc() {
remote=$1; shift
ssh "$remote" "$(printf "%q " "$@")"
}
$ printf "%q " touch "a test file" "another file"
touch a\ test\ file another\ file
$ sshc user@server touch "a test file" "another file"
%%
:%
문자를 프린트할때 사용합니다.%c
: 인수의 첫번째 문자를 프린트합니다.%(FORMAT)T
: FORMAT 에따라 date-time 을 프린트합니다.
$ printf "foo %%%s%%\n" bar
foo %bar%
$ printf "%c %c\n" abc def
a d
$ printf "today is %(%Y-%m-%d)T\n"
today is 2015-08-31
%n
: 앞에서 출력된 문자수를 인수로 주어진 변수에 대입합니다. ( bash only )
$ printf "12345%n6789%n\n" num1 num2
123456789
$ echo $num1 $num2
5 9
Width
N
: field width 를 설정합니다.*
: field width 값을 인수로 받을 수 있습니다.
$ printf "%d %d %d\n" 100 200 300
100 200 300
$ printf "%10d %10d %10d\n" 100 200 300 # field width 를 10 으로 설정
100 200 300
$ printf "%*d %*d %*d\n" 10 100 15 200 20 300 # 10, 15, 20 은 각각 * 에 대응하는 값
100 200 300
# 구분선 만들기
$ printf -v sep '%*s' 50 ; echo "${sep// /-}"
--------------------------------------------------
Flags
-
: field width 내에서 값을 left 정렬합니다. ( default 는 right 정렬입니다. )
$ printf "%10d %10d %10d\n" 100 200 300
100 200 300
$ printf "%-10d %-10d %-10d\n" 100 200 300
100 200 300
0
: field width 에 맞게 zero padding 합니다.
$ printf "%06d\n" 12 345 6789
000012
000345
006789
+
: 숫자에+
,-
sign 기호를 붙여서 표시합니다.
$ printf "%+10d %+10d %+10d\n" 100 -200 +300
+100 -200 +300
space
:+
를 사용하지 않을경우 sign 자리에 space 를 두어 정렬합니다.
$ printf "%d\n" 100 -200 +300
100
-200
300
$ printf "% d\n" 100 -200 +300
100
-200
300
'
: 1000 의 자리마다,
를 넣어 표시합니다. ( bash only )
$ printf "%'d\n" 123456789
123,456,789
#
: alternative format 을 사용할 수 있습니다.
%#o
은 값을 octal number 로 표시할때 앞에 0
을 붙입니다.
$ printf "%#o\n" 10
012
%#x
, %#X
은 값을 hexadecimal number 로 표시할때 앞에 0x
, 0X
를 붙입니다.
$ printf "%#x %#X\n" 10 30
0xa 0X1E
%#g
, %#G
은 precision 내에서 trailing zero 를 붙입니다.
$ printf "%g\n" 12.34
12.34
$ printf "%#g\n" 12.34
12.3400
Precision
.
을 이용하면 왼쪽에는 field width 를 오른쪽에는 precision 을 설정할 수 있습니다.
field width 크기는 precision 을 포함합니다.
.N
: precision 값을 설정합니다..*
: precision 값을 인수로 받을 수 있습니다.
$ printf "%f\n" 123.987654321
123.987654
$ printf "%.3f\n" 123.987654321 # precision 을 3 으로 설정
123.988 # 소수 넷째 자리에서 반올림이 된다
$ printf "%.*f\n" 3 123.987654321 # '*' 을 이용하여 precision 값을 인수로 받음
123.988
%f
와 %g
는 precision 값을 처리하는 방식이 다릅니다.%f
는 소수점 이후의 개수를 나타내고 %g
는 전체 유효숫자 개수를 나타냅니다.
$ printf "%.5f\n" 123.12345678 # 소수점 이후 5개
123.12346
$ printf "%.5g\n" 123.12345678 # 전체 유효숫자 5개
123.12
$ printf "%.5f\n" 0.0012345678
0.00123
$ printf "%.5g\n" 0.0012345678
0.0012346
%.s
or %.0s
는 해당 인수를 출력에서 제외하는 효과를 갖습니다.
$ printf "%5d%5d%.s%.0s%5d\n" 11 22 33 44 55
11 22 55
예제 )
0 ~ 127 까지 숫자를 decimal, octal, hexadecimal 로 출력하기
$ for ((x=0; x <= 127; x++)); do
> printf '%3d | %04o | 0x%02x\n' $x $x $x
> done
0 | 0000 | 0x00
1 | 0001 | 0x01
2 | 0002 | 0x02
...
...
125 | 0175 | 0x7d
126 | 0176 | 0x7e
127 | 0177 | 0x7f
1 ~ 2 자리로 되어있는 hexadecimal number 를 2 자리로 맞추기
$ mac_addr="0:13:ce:7:7a:ad"
$ printf "%02x:%02x:%02x:%02x:%02x:%02x\n" 0x${mac_addr//:/ 0x}
00:13:ce:07:7a:ad
현재 라인 우측 끝에 메시지 출력하기tput cols
은 현재 터미널 columns 수를 출력. echo $COLUMNS
과 동일
printf "%*s\n" $(tput cols) "hello world"
Quiz
----------
horizontal line 만들기
bash$ printf '%.s-' {1..50}; echo
--------------------------------------------------
sh$ printf '%.s-' $(seq 50 | xargs); echo
--------------------------------------------------
쉘에서는 echo 명령으로 -n
스트링을 프린트할 수가 없습니다.
왜냐하면 -n
을 옵션으로 인식하기 때문인데요. 어떻게 프린트할 수 있을까요?
$ echo "-n"
$ # -n 가 표시되지 않는다.
$ echo -- "-n"
-- -n
# printf 명령을 이용하면 됩니다.
$ printf -- -n
-n