Polecenie printf

man printf

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.

Sposób interpretowania argumentów liczbowych przez bash/printf

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

Ciągi formatujące

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 printf w Bash.

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 (a-f jako symboli dla cyfr 10-15). Ciąg formatujący %X daje te same rezultaty jednak używa duzych liter (A-F jako symboli dla cyfr 10-15).

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 <N>±e<N>. Opcja %E robi to samo jednak wypisuje liczbę w formacie <N>±E<N> (duże E, a nie małe e).

Zapewne się zastanawiasz po co wypis z E/e jest to tak zwana notacja naukowa. Jest ona pomocna przy zapisywaniu bardzo dużych/małych liczb w stosunkowo zwięzłej formie. Na przykład liczbę 0,00000327114 można zapisać jako 3,27114 * 10^-6, czyli 3,27114e-6. Łatwe prawda?

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 <N>±e<N>. Opcja %G robi to samo jednak wypisuje liczbę w formacie <N>±E<N> (duże E, a nie małe e).

Zapewne się zastanawiasz po co wypis z E/e jest to tak zwana notacja naukowa. Jest ona pomocna przy zapisywaniu bardzo dużych/małych liczb w stosunkowo zwięzłej formie. Na przykład liczbę 0,00000327114 można zapisać jako 3,27114 * 10^-6, czyli 3,27114e-6. Łatwe prawda?

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 C99 hexadecimal floating-point. Opcja %A robi to samo jednak wypisuje liczbę w formacie <N>±E<N> (duże E, a nie małe e).

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 (char).

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. string), czyli całą zmienną.

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 %n funkcji printf korzystał w skryptach - traktuję ją jako ciekawostkę.

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 (FORMAT). FORMAT dokładnie jest opisany strftime(3) (man 3 strftime) oraz jest dostępny przy opisie polecenia date.

Przekazany argument jest liczbą sekund od Epoch (początku ery Unixa), format ten w poleceniu printf ma dwa parametry specjalne:

  • -1 - aktualny czas
  • -2 - czas startu powłoki (czas uruchomienia Bash)

Jeżeli nie został przekazany, żaden argument to domyślnie komenda zakłada, że zachowa sie tak jakby podano -1 i wypisze aktualną datę/czas zgodnie z zadanym formatem.

## 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 printf nie obsługuje poprawnie 64 bitowej reprezentacji czasu. Całe szczeście jest jeszcze trochę czasu by to poprawić (dokładnie do 2147483647-12-31 23:59:59 CET) :).

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 2147483647, czyli MAX_INT_32 :). Mamy tu do czynienia z przekroczeniem licznika i „zawinięciem zmiennej”. Czy można ją wykorzystać w niecnym celu - może może

Jak do tego doszliśmy.

%%

Brak konwersji - po prostu wypisuje znak % (procent).

johny@ThinkPad:~$ printf "%%d %d\n" "1024"
%d 1024
johny@ThinkPad:~$ printf "%%d %d\n" "1024" "2048"
%d 1024
%d 2048

Flagi do ciągów formatujących

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.

  • Jesli wypisywany tekst będzie krótszy zostanie on „dopełniony” spacjami.
  • Jeżeli tekst będzie dłuższy pole zostanie rozszerzone.
johny@ThinkPad:~$ printf "== %5s ==\n" "ala_ma_kota"
== ala_ma_kota ==
johny@ThinkPad:~$ printf "== %5s ==\n" "ala"
==   ala ==
.

Flaga „kropka” . w połączeniu z szerokością pola powoduje ucięcie tesktu jeżeli ten jest za długi.

Ostrzeżenie

Zapis "%.s jest nieudokomentowanym sposobem na ukrycie wartości zmiennej (wpisywana jest długość 0).

Podpowiedź

Zapis z . może także odnosić się do „Precyzji liczb zmiennoprzecinkowych”

johny@ThinkPad:~$ printf "== %.5s ==\n" "ala_ma_kota"
== ala_m ==
johny@ThinkPad:~$ printf "== %.s ==\n" "ala_ma_kota"
==  ==
*

Flaga „gwiazdka” * oznacza, że długość tekstu będzie przekazana przed argumentem jako liczba.

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” - powoduje wyrównanie tekstu do lewej. Standardowo tekst jest wyrównany do prawej.

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 +, dla ujemnych -)

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 LC_NUMERIC ma wpływ na wyświetlanie.

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 #.

  • %#o - Liczba całkowita wypisywana jako ósemkowa z poprzedzającym zerem (gdy 0 - nie dotyczy)
  • %#x, %#X - Liczba całkowita wypisywana jako szesnastkowa poprzedzona 0x/0X (gdy 0 - nie dotyczy)
  • %#g, %#G - Liczba zmienno przecinkowa o pojedynczej precyzji wypisana do ustalonej precyzji na ogól zera poprzedzające nie są wypisane
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 %d, %o, %x, %X wypisują „przecinek” nawet jeśli nie ma żadnych cyfr w mantysie uzasadniających to zachowanie.

Precyzja liczb zmiennoprzecinkowych

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

Escape codes

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 \ (backslash)

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” (carriage-return). Powoduje to przejście kursora do poczatku aktualnego wiersza.

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 <NNN> jako liczbę ósemkową i wypisuje odpowiedni znak jaki jest pod tą liczbą

johny@ThinkPad:~$ printf "\143 \077\n"
c ?
\x<NNN> \u<NNNN> \U<NNNNNNNN>

Interpetuje <NNN> jako liczbę szesnastkową i wypisuje odpowiedni znak ASCII. Liczbę szesnastkową mozna podac jako: 3 cyfry (\x<NNN>), 4 cyfry (\u<NNNN>) i 8 cyfr (\U<NNNNNNNN>).

johny@ThinkPad:~$ printf "\x63 \u0063 \U000063\n"
c c c
\c

Zakończy wypisywanie podobnie jak w przypadku \c używanego przy komendzie echo -e. printf nie wypisze nic więcej gdy trafi przy formaterze %b w zmiennej na escape code \c (przykład poniżej).

Ostrzeżenie

Ten escape code działa tylko i wyłącznie przy skorzystaniu z formatu %b.

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

Przykłady użycia

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