printf: printf [-v var] format [argumenty] Formatowanie i wypisanie ARGUMENTÓW zgodnie z FORMATEM. Opcje: -v ZMIENNA przypisanie wyjścia do podanej ZMIENNEJ powłoki zamiast wypisywania na standardowym wyjściu FORMAT jest łańcuchem znakowym zawierającym trzy rodzaje obiektów: zwykłe znaki, które są kopiowane na standardowe wyjście; znaki sekwencji sterujących, które są przekształcane i kopiowane na standardowe wyjście; oraz sekwencje formatujące, z których każda powoduje wypisanie kolejnego argumentu. Poza standardowymi sekwencjami formatującymi opisanymi w printf(1) oraz printf(3), printf interpretuje: %b rozwinięcie sekwencji z odwrotnym ukośnikiem w odpowiadającym argumencie %q cytowanie argumentu w sposób umożliwiający użycie na wejściu powłoki %(fmt)T wypisanie łańcucha daty-czasu otrzymanego z użycia FMT jako łańcucha formatującego dla strftime(3) Format jest używany ponownie w razie potrzeby w celu pochłonięcia wszystkich argumentów. Jeśli argumentów jest mniej, niż wymaga format, nadmiarowe sekwencje zachowują się tak, jakby podano wartość zerową lub łańcuch pusty. Stan wyjściowy: Zwracana jest prawda, chyba że podano błędną opcję lub zapis albo przypisanie zakończy się niepowodzeniem.
Format liczby | Opis (za N podstawiamy cyfry) |
---|---|
N |
Liczba w systemie dziesiętnym - zawiera cyfry od 0 - 9 |
0N |
Liczba w systemie ósemkowym - zawiera cyfry od 0 - 7 |
0xN ,
0XN |
Liczba w systemie szesnastkowym - zawiera cyfry od 0 - F |
Funkcja printf
wypisuje tekst na standardowe wyjście (tj. do stdout), formatuje ona tekst zgodnie z podanym formatem/specyfikatorem opisanym poniżej.
W powłoce rozpoznawane są tylko nastepujące modyfikatory diouxXfeEgGaAcs
Każdy podany format spodziewa się argumentu do funkcji.
Każdy z tych specyfikatorów ma inną nazwę i funkcję - ale wszystkie mają jedną cechę sformatować i wstawić odpowiednią daną w miejscu swojego występowania.
Wszystko stanie się jasne po przejrzeniu paru przykładów.
Podpowiedź
Nim rozpoczniemy czytanie poniższej tabeli zalecam zapoznanie się z rozdziałem o poleceniu echo,
a także z rozdziałem „Cytowanie zmiennych” ponieważ te polecenia są powiązane z poleceniem printf
.
Format | Opis |
---|---|
%b |
Wypisuje podane argumenty interpretując w nich „zaquotowane/escapowane backslashe”. johny@ThinkPad:~$ foo='\$a'
johny@ThinkPad:~$ bar='\\$a'
johny@ThinkPad:~$ baz='\\\$a'
johny@ThinkPad:~$ printf "%b %b %b\n" "$foo" "$bar" "$baz"
\$a \$a \\$a
|
%q |
Wypisuje argumenty w zaquotowany sposób, można użyć do przeczyszczenia wejścia programu. johny@ThinkPad:~$ foo='$bar' ## single quotes no expansion
johny@ThinkPad:~$ printf "%q\n" "$foo"
\$bar
|
%d ,
%i |
Wypisuje argument jako liczbę całkowita (dodatnią/ujemną). Ten modyfikator jest najczęstszym powodem wykorzystania
polecenia Bardzo czesto jest łączony z dodatkowymi opcjami - zobacz sekcję Flagi do ciągów formatujących. johny@ThinkPad:~$ printf "%d %d %i\n" 3 14 15
3 14 15
johny@ThinkPad:~$ printf "%d %d %i\n" -3 -14 -15
-3 -14 -15
johny@ThinkPad:~$ locale | grep -i LC_NUMERIC
LC_NUMERIC=pl_PL.UTF-8
johny@ThinkPad:~$ PI="3,141592653589793238"
johny@ThinkPad:~$ printf "%d %i\n" "$PI" "$PI"
bash: printf: 3,141592653589793238: invalid number
bash: printf: 3,141592653589793238: invalid number
3 3
johny@ThinkPad:~$ locale | grep -i LC_NUMERIC
LC_NUMERIC=pl_PL.UTF-8
johny@ThinkPad:~$ PI="3.141592653589793238"
johny@ThinkPad:~$ printf "%d %i\n" "$PI" "$PI"
bash: printf: 3.141592653589793238: invalid number
bash: printf: 3.141592653589793238: invalid number
3 3
|
%u |
Wypisuje argument traktując go jako liczbę całkowita bez znaku (zwróć uwagę na przykłady z podaniem liczb ujemnych). Bardzo czesto jest łączony z dodatkowymi opcjami - zobacz sekcję Flagi do ciągów formatujących. johny@ThinkPad:~$ printf "%u %u %u\n" 3 14 15
3 14 15
johny@ThinkPad:~$ printf "%u %u %u\n" -3 -14 -15
18446744073709551613 18446744073709551602 18446744073709551601
|
%o |
Wypisuje argument jako liczbę w systemie ósemkowym. Stosunkowo rzadko używany. johny@ThinkPad:~$ printf "%o %o %o %o %o\n" 3 7 8 15 16
3 7 10 17 20
|
%x ,
%X |
Wypisuje argument jako liczbę liczbę szesnastkową (bez znaku - dodatnią)
z małymi literami ( W samym Bashu używane sporadycznie, jednak zalecam zaznajomić się ze składnią i wynikami działania (bo w innych językach używane często). johny@ThinkPad:~$ printf "%x %x %x\n" 3 14 15
3 e f
johny@ThinkPad:~$ printf "%x %x %x\n" -3 -14 -15
fffffffffffffffd fffffffffffffff2 fffffffffffffff1
johny@ThinkPad:~$ printf "%X %X %X\n" 3 14 15
3 E F
johny@ThinkPad:~$ printf "%X %X %X\n" -3 -14 -15
FFFFFFFFFFFFFFFD FFFFFFFFFFFFFFF2 FFFFFFFFFFFFFFF1
|
%f |
Interpretuje i wypisuje argument jako liczbę zmiennoprzecinkową o pojedynczej precyzji. Informacja Na wynik polecenia mają wpływ ustawienia lokalizacji (internacjonalizacji) systemu na którym jest uruchomiony skrypt (ale jest to dosyć zaawansowany temat). johny@ThinkPad:~$ locale | grep -i LC_NUMERIC
LC_NUMERIC=pl_PL.UTF-8
johny@ThinkPad:~$ printf "%f %f\n" "3,1415" "-3,1415"
3,141500 -3,141500
johny@ThinkPad:~$ printf "%f %f\n" "3.1415" "-3.1415"
bash: printf: 3.1415: invalid number
bash: printf: -3.1415: invalid number
0,000000 0,000000
|
%e ,
%E |
Interpretuje i wypisuje argument jako liczbę zmiennoprzecinkową o pojedynczej precyzji i wypisuje ją w formacie Zapewne się zastanawiasz po co wypis z Informacja Na wynik polecenia mają wpływ ustawienia lokalizacji (internacjonalizacji) systemu na którym jest uruchomiony skrypt (ale jest to dosyć zaawansowany temat). johny@ThinkPad:~$ locale | grep -i LC_NUMERIC
LC_NUMERIC=pl_PL.UTF-8
johny@ThinkPad:~$ printf "%e %E\n" "3,1415" "-3,1415"
3,141500e+00 -3,141500E+00
johny@ThinkPad:~$ printf "%e %E\n" "3.1415" "-3.1415"
bash: printf: 3.1415: invalid number
bash: printf: -3.1415: invalid number
0,000000e+00 0,000000E+00
johny@ThinkPad:~$ locale | grep -i LC_NUMERIC
LC_NUMERIC=pl_PL.UTF-8
johny@ThinkPad:~$ PI="3,141592653589793238"
johny@ThinkPad:~$ printf "%e %E\n" "$PI" "$PI"
3,141593e+00 3,141593E+00
|
%g ,
%G |
Interpretuje i wypisuje argument jako liczbę zmiennoprzecinkową o podwójnej precyzji i wypisuje ją w formacie Zapewne się zastanawiasz po co wypis z Informacja Na wynik polecenia mają wpływ ustawienia lokalizacji (internacjonalizacji) systemu na którym jest uruchomiony skrypt (ale jest to dosyć zaawansowany temat). johny@ThinkPad:~$ locale | grep -i LC_NUMERIC
LC_NUMERIC=pl_PL.UTF-8
johny@ThinkPad:~$ PI="3,141592653589793238"
johny@ThinkPad:~$ printf "%g %G\n" "$PI" "$PI"
3,14159 3,14159
|
%a ,
%A |
Interpretuje i wypisuje argument jako liczbę zmiennoprzecinkową o podwójnej precyzji jako Jeżeli chciałbyś używać tego formatu to polecam zapoznać się ze szczegółami standardu IEEE754 by np. zrozumieć jak komputer przechowuje liczby w pamięci. Informacja Na wynik polecenia mają wpływ ustawienia lokalizacji (internacjonalizacji) systemu na którym jest uruchomiony skrypt (ale jest to dosyć zaawansowany temat). johny@ThinkPad:~$ locale | grep -i LC_NUMERIC
LC_NUMERIC=pl_PL.UTF-8
johny@ThinkPad:~$ PI="3,141592653589793238"
johny@ThinkPad:~$ printf "%a %A\n" "$PI" "$PI"
0xc,90fdaa22168c233p-2 0XC,90FDAA22168C233P-2
|
%c |
Interpretuje i wypisuje argument jako pojedynczy znak ( Ostrzeżenie Zostanie wypisany tylko pierwszy znak zmiennej (niezaleznie od tego jaką zmienna ma długość). johny@ThinkPad:~$ printf "%c\n" "foo_bar_baz"
f
|
%s |
Interpretuje i wypisuje argument jako ciąg znaków (tzw. johny@ThinkPad:~$ printf "%s\n" "foo_bar_baz"
foo_bar_baz
|
%n |
Przypisuje do zmiennej o nazwie podanej jako argument dla tego ciągu liczbę wypisanych do tej pory znakdów. Nie można wskazać indexu dla zmiennej tablicowej. Jeżeli podano tablice, wartość przypisywana jest do zerowego elementu zmiennej tablicowej. Informacja Osobiście nie widziałem by ktokolwiek z modyfikatora johny@ThinkPad:~$ printf "%s%n\n" "foo_bar_baz" 'wypisano'
foo_bar_baz
johny@ThinkPad:~$ echo $wypisano
11
|
%(FORMAT)T |
Interpretuję argument liczbowy jako datę i wypisuje ją zgodnie z zadanym formatem ( Przekazany argument jest liczbą sekund od
Jeżeli nie został przekazany, żaden argument to domyślnie komenda zakłada, że zachowa sie
tak jakby podano ## Wszystkie przykłady na polskich ustawieniach
## All examples on polish locales
johny@ThinkPad:~$ locale | grep -i LC_TIME
LC_TIME=pl_PL.UTF-8
johny@ThinkPad:~$ printf '%(%Y-%m-%d %H:%M:%S %Z (%A))T\n' -1
2019-02-09 21:10:21 CET (sobota)
johny@ThinkPad:~$ printf '%(%Y-%m-%d %H:%M:%S %Z (%A))T\n' -2
2019-02-09 21:09:09 CET (sobota)
johny@ThinkPad:~$ printf "%(%s)T\n" -1
1549746621
johny@ThinkPad:~$ printf '%(%Y-%m-%d %H:%M:%S %Z (%A))T\n' 1549746621
2019-02-09 22:10:21 CET (sobota)
johny@ThinkPad:~$ printf '%(%Y-%m-%d %H:%M:%S %Z (%A))T\n' 0 ## Epoch - Unix Era Start
1970-01-01 01:00:00 CET (czwartek)
johny@ThinkPad:~$ printf '%(%Y-%m-%d %H:%M:%S %Z (%A))T\n' 86400 ## one day later
1970-01-02 01:00:00 CET (piątek)
johny@ThinkPad:~$ printf '%(%Y-%m-%d %H:%M:%S %Z (%A))T\n' 2147483647 ## max INT32
2038-01-19 04:14:07 CET (wtorek)
Ostrzeżenie Wygląda na to, że johny@ThinkPad:~$ printf '%(%Y-%m-%d %H:%M:%S %Z (%A))T\n' 9223372036854775807 ## max INT64 (long)
1970-01-01 01:00:00 CET (czwartek)
johny@ThinkPad:~$ echo $?
0
johny@ThinkPad:~$ EPOCH=67767976233529199
johny@ThinkPad:~$ printf '%(%Y-%m-%d %H:%M:%S %Z (%A))T\n' $EPOCH
2147483647-12-31 23:59:59 CET (wtorek)
johny@ThinkPad:~$ EPOCH=$(($EPOCH + 1))
johny@ThinkPad:~$ printf '%(%Y-%m-%d %H:%M:%S %Z (%A))T\n' $EPOCH
-2147483648-01-01 00:00:00 CET (środa)
Czy zauważyliście co jest problemem?
Tak! Maksymalny rok to |
%% |
Brak konwersji - po prostu wypisuje znak johny@ThinkPad:~$ printf "%%d %d\n" "1024"
%d 1024
johny@ThinkPad:~$ printf "%%d %d\n" "1024" "2048"
%d 1024
%d 2048
|
By zapewnić jak największa elastyczność przy formatowaniu wyjścia komenda printf
pozwala na uzywanie modyfikatorów do ciągów formatujących zmienne.
Flagi najcześciej zmieniają działanie ciągów formattujących w zakresie szerokości pola z tekstem, precyzji wypisywanych liczb, itp.
Flagi są wstawiane pomiędzy %
i znak okreslający format.
% flaga s
^ ^ ^
| | |
| | -------------- ciąg formatujący "%s" - czyli wypisz string
| |
| ---------------------- flaga dla ciągu formatującego powodująca jego specyficzne działanie
|
------------------------------ rozpoczęcie ciągu formatującego "%s"
Poniżej przedstawiam przykład wykorzystania modyfikatora dla łancucha znakowego
johny@ThinkPad:~$ printf "=== %50s ===\n" "To pole ma 50 znaków ..."
=== To pole ma 50 znaków ... ===
johny@ThinkPad:~$ printf "=== %-50s ===\n" "To pole ma 50 znaków ..."
=== To pole ma 50 znaków ... ===
Flaga | Działanie flagi i przykład |
---|---|
<N> |
Dowolny numer. Okresla minimalną szerokość wypisywanego pola.
johny@ThinkPad:~$ printf "== %5s ==\n" "ala_ma_kota"
== ala_ma_kota ==
johny@ThinkPad:~$ printf "== %5s ==\n" "ala"
== ala ==
|
. |
Flaga „kropka” Ostrzeżenie Zapis Podpowiedź Zapis z johny@ThinkPad:~$ printf "== %.5s ==\n" "ala_ma_kota"
== ala_m ==
johny@ThinkPad:~$ printf "== %.s ==\n" "ala_ma_kota"
== ==
|
* |
Flaga „gwiazdka” johny@ThinkPad:~$ printf "== %*s ==\n" 7 "ala_ma_kota"
== ala_ma_kota ==
johny@ThinkPad:~$ printf "== %.*s ==\n" 7 "ala_ma_kota"
== ala_ma_ ==
|
- |
Flaga „myślnik” johny@ThinkPad:~$ printf "== %-5s ==\n" "lol"
== lol ==
johny@ThinkPad:~$ printf "== %5s ==\n" "lol"
== lol ==
|
0 |
Dopełnia pole do długości wskazanej zerami (0), a nie spacjami. johny@ThinkPad:~$ printf "== %5d ==\n" "42"
== 42 ==
johny@ThinkPad:~$ printf "== %05d ==\n" "42"
== 00042 ==
|
<spacja> |
Wyrównaj liczby dodatnie spacjami do długości pola, wstaw przed liczbą ujemną znak minus ( johny@ThinkPad:~$ printf "== % 5d ; % 5d ==\n" "42" "-42"
== 42 ; -42 ==
|
+ |
Do liczby jaka zostanie wypisana zostanie zawsze dodany jej znak (dla dodatnich johny@ThinkPad:~$ printf "== %+5d ; %+5d ==\n" "42" "-42"
== +42 ; -42 ==
|
' |
Dla konwersji liczb w formacie dziesętym dodaje separator „dla tysięcy” do części całkowitej liczby.
Zmienna johny@ThinkPad:~$ printf "== %'5d ==\n" "10241024"
== 10 241 024 ==
johny@ThinkPad:~$ printf "== %'.10f ==\n" "10241024,10241024"
== 10 241 024,1024102400 ==
|
# |
„Alternatywny format” dla liczb - modyfikator/flaga
johny@ThinkPad:~$ printf '%#o + %#x + %#X + %#g + %#G\n' 12 12 12 12,1234 12,1234
014 + 0xc + 0XC + 12,1234 + 12,1234
johny@ThinkPad:~$ printf '%#o + %#x + %#X + %#g + %#G\n' 0 0 0 0 0
0 + 0 + 0 + 0,00000 + 0,00000
Informacja Wszystkie formaty liczbowe z wyjątkiem |
Precyzja wypisywania liczby zmienno przecinkowej (o pojedynczej jak i podwójnej precyzji) jest specyfikowana z użyciem kropki .<LICZBA>
,
gdzie <LICZBA>
oznaczają precyzję.
Jeżeli <LICZBA>
jest gwiazdką *
, precyzja liczby może być odczytana jako argument poprzedzający liczbę do wypisania:
johny@ThinkPad:~$ printf "%.*f\n" 10 4,3
4,3000000000
Dla liczb całkowitych <LICZBA> oznacza wielkość pola do którego musi się zmieścić liczba do wypisania - dopełnionego zerami!
johny@ThinkPad:~$ printf "%.*d\n" 10 4
0000000004
Sa to znaki poprzedzone backslashem.
Gdy polecenie printf
znajdzie taki znak gdziekolwiek w ciągu formatującym lub
w argumencie podanym do formatu %b
wtedy zmienia trochę swoje działanie.
Escape code | Opis |
---|---|
\\ |
Wypisuje znak johny@ThinkPad:~$ printf '\\\n'
\
|
\a |
Wypisuje znak „alarm” (znak o kodzie ASCII 7 (dzisiętnie)). W większości systemów alarm jest wyłączony. O tym jak właczyć alarm, czyli tzw. bell można przeczytać na StackOverflow. |
\b |
Wypisuje backspace johny@ThinkPad:~$ printf "Koty suxx\b\b\b\br0x\n"
Koty r0xx
|
\f |
Wypisuje „wysunięcie strony” - form feed .
W większości przypadków oznacza to przejście do nowej linii. |
\n |
Wypisuje znak nowej linii johny@ThinkPad:~$ printf "ala\nma\nkota\n"
ala
ma
kota
|
\r |
Wypisuje tzw. „powrót kartki” ( johny@ThinkPad:~$ printf "ala ma\rwielkiego\rkota\n"
kotakiego
|
\t |
Wypisuje tabulator poziomy johny@ThinkPad:~$ printf "ala\tma\twielkiego\tkota\n"
ala ma wielkiego kota
|
\v |
Wypisuje tabluator pionowy johny@ThinkPad:~$ printf "ala\vma\vwielkiego\vkota\n"
ala
ma
wielkiego
kota
|
\" |
Wypisuje johny@ThinkPad:~$ printf "\"\n"
"
|
\? |
Wypisuje johny@ThinkPad:~$ printf "\?\n"
?
|
\<NNN> ,
\0<NN> |
Interpretuje johny@ThinkPad:~$ printf "\143 \077\n"
c ?
|
\x<NNN>
\u<NNNN>
\U<NNNNNNNN> |
Interpetuje johny@ThinkPad:~$ printf "\x63 \u0063 \U000063\n"
c c c
|
\c |
Zakończy wypisywanie podobnie jak w przypadku Ostrzeżenie Ten escape code działa tylko i wyłącznie przy skorzystaniu z formatu johny@ThinkPad:~$ printf "%s\n%b\n%s\n" 'tekst' 'tekst' 'tekst'
tekst
tekst
tekst
johny@ThinkPad:~$ printf "%s\n%b\n%s\n" 'tekst' '\c' 'tekst'
tekst
johny@ThinkPad:~$ printf "%s\n%s\n%s\n" 'tekst' '\c' 'tekst'
tekst
\c
tekst
|
W powyższym opisie było bardzo wiele przykładów użycia poleceina printf
,
poniżej zamieszczam jeszcze dodatkowe, które są ciekawe z różnych względów.
johny@ThinkPad:~$ SURNAME=G
johny@ThinkPad:~$ FIRSTNAME=TOM
johny@ThinkPad:~$ printf "Surname: %s\nName: %s\n" "$SURNAME" "$FIRSTNAME"
Surname: G
Name: TOM
Konwersja pomiędzy systemem ósemkowym, a dzisiętnym w Bash
johny@ThinkPad:~$ printf '%d\n' "012" ## wypisz liczbę ósemkowa jako dzisiętną
10
johny@ThinkPad:~$ printf '%o\n' "10" ## wypisz liczbę dziesiętna jako ósemkową
12
Niewielka tabela kodów ASCII (od 0 - 20)
johny@ThinkPad:~$ {
printf '| %10s | %10s | %10s |\n' "decimal" "octal" "hex"
for ((x=0; x <= 20; x++)); do
printf '| %10d | %010o | 0x%010x |\n' "$x" "$x" "$x"
done
}
| decimal | octal | hex |
| 0 | 0000000000 | 0x0000000000 |
| 1 | 0000000001 | 0x0000000001 |
| 2 | 0000000002 | 0x0000000002 |
| 3 | 0000000003 | 0x0000000003 |
| 4 | 0000000004 | 0x0000000004 |
| 5 | 0000000005 | 0x0000000005 |
| 6 | 0000000006 | 0x0000000006 |
| 7 | 0000000007 | 0x0000000007 |
| 8 | 0000000010 | 0x0000000008 |
| 9 | 0000000011 | 0x0000000009 |
| 10 | 0000000012 | 0x000000000a |
| 11 | 0000000013 | 0x000000000b |
| 12 | 0000000014 | 0x000000000c |
| 13 | 0000000015 | 0x000000000d |
| 14 | 0000000016 | 0x000000000e |
| 15 | 0000000017 | 0x000000000f |
| 16 | 0000000020 | 0x0000000010 |
| 17 | 0000000021 | 0x0000000011 |
| 18 | 0000000022 | 0x0000000012 |
| 19 | 0000000023 | 0x0000000013 |
| 20 | 0000000024 | 0x0000000014 |
Formatowanie wyjścia - dostosowanie długości kolumn do tekstu.
Kodzik znalazłem na StackOverflow ,
ale uważam że warto go przesledzić by poznać mozliwości polecenia printf
.
#!/bin/bash
list=(localhost google.com nowhere)
C=1
for M in "${list[@]}"
do
machine_indented=$(printf '%-20s' "$M")
machine_indented=${machine_indented// /.}
if ping -q -c 1 "$M" &>/dev/null ; then
printf "(%2d) %s CONNECTION OK\n" "$C" "$machine_indented"
else
printf "(%2d) %s CONNECTION FAIL\n" "$C" "$machine_indented"
fi
((C=C+1))
done
johny@ThinkPad:~$ bash test.sh
( 1) localhost........... CONNECTION OK
( 2) google.com.......... CONNECTION OK
( 3) nowhere............. CONNECTION FAIL
Czasami można skorzystać z printf
do generowania pseudo tabelek.
Kod pobrany z linuxconfig.org.
#/bin/bash
divider===============================
divider=$divider$divider
header="\n %-10s %8s %10s %11s\n"
format=" %-10s %08d %10s %11.2f\n"
width=43
printf "$header" "ITEM NAME" "ITEM ID" "COLOR" "PRICE"
printf "%$width.${width}s\n" "$divider"
printf "$format" \
Triangle 13 red 20 \
Oval 204449 "dark blue" 65.656 \
Square 3145 orange .7
johny@ThinkPad:~$ bash test.sh
ITEM NAME ITEM ID COLOR PRICE
===========================================
Triangle 00000013 red 20,00
Oval 00204449 dark blue 65,66
Square 00003145 orange 7,00