Printf

Материал из Ай да Linux Wiki
Перейти к навигации Перейти к поиску

Printf как замена команды echo

Эта команда была создана для замены всем знакомой команды echo. Возможности команды echo ограничены, кроме того, в разных ветках Unix'а оказались разные ее версии, что приводит к несовместимости. Поэтому Posix рекомендует пользоваться командой printf. Команда printf выводит АРГУМЕНТ на стандартный вывод (как правило, экран дисплея), используя при этом определенный ФОРМАТ.

printf 'ФОРМАТ' 'АРГУМЕНТ'

Эта команда была создана для замены всем знакомой команды echo (настолько древней, что даже имя ее автора не известно).


Самое первое, что следует прояснить: по умолчанию команда printf не переводит строку по завершении. Это выглядит так:

 [ya@antony ~]$ printf '%s' 'alex'
 
 alex[ya@antony ~]$  

Следующее приглашение командной строки находится на той же самой строке что и вывод предыдущей команды. Это очень неудобно, поэтому в ФОРМАТ приходится добавлять символ новой строки (\n):

 [ya@antony ~]$ printf '%s\n' 'alex'
 
 alex
 
 [ya@antony ~]$ 

Приглашение переехало на новую строку, и все обрело привычный вид. В дальнейшем я не стану приводить приглашение целиком, ограничусь знаком доллара.

Вот как выглядит команда printf в виде, полностью дублирующем команду echo:

  $ printf '%b\n' 'Это заклинание заменит команду echo'
  
  Это заклинание заменит команду echo

Обратите внимание, что мы взяли аргумент в кавычки, чтобы получить его в виде одной строки. Если бы мы этого не сделали, то имели бы столбик, так как программа воспринимает выражения, разделенные пробелом, как множественные аргументы, и обрабатывает каждый в соответствии с заданным форматом:

 $ printf '%b\n' Это заклинание заменит команду echo
 
 Это 
 
 заклинание 
 
 заменит 
 
 команду 
 
 echo

Если нам нужно использовать команду printf для просмотра переменных окружения, то кавычки не нужны:

 $ printf '%b\n' $PATH
 
 /home/ya/bin:/usr/local/bin:/usr/bin:/bin:/usr/bin:/usr/games:/usr/X11R6/bin

Если же мы возьмем аргумент в кавычки, то он будет воспринят просто как выражение и воспроизведен дословно:

 $ printf '%b\n' '$PATH'
 
 $PATH

Но довольно о замене команды echo, займемся непосредственно командой printf.

Описание и использование

Представление аргумента

N Нормальное десятичное число. Например 177

0N Восьмеричное число. Например 024.

0xN и 0XN Шестнадцатеричные числа. Например 0?41.

(обычные кавычки перед любой буквой) Интерпретируется как кодовый номер этой буквы в текущей кодировке. С кириллицей не работает.

'А (одинарные кавычки перед любой буквой) Интерпретируется как кодовый номер этой буквы в текущей кодировке. С кириллицей не работает.

Форматы команды printf

Вообще говоря, синтаксис команды printf взят от функции printf() языка программирования Си (и еще дюжины других). Но далеко не все знакомы с Си, поэтому мы внимательно рассмотрим все тонкости синтаксиса этой команды.

ФОРМАТ пишется в командной строке непосредственно после самой команды и заключается в кавычки - двойные или одинарные. Собственно говоря, кавычки нужны не всегда, но лучше их ставить, во избежание недоразумений. Это полезная привычка. (А ведь большинство привычек - вредные).

%b Рассматривает аргумент как строку, при этом интерпретирует все управляющие символы, содержащиеся в ней.

%s Рассматривает аргумент как просто как строку.

%c Рассматривает аргумент как символ, при этом берется первый символ выражения или строки.

%q Преобразует строку к виду, пригодному к использованию в качестве ввода в шелл.

Здесь необходимы пояснения. Допустим, мы хотим напечатать на экране фразу:

 Ваш,
 
 Алексей Дмитриев

Для этого дадим следующую команду:

 $ printf '%b\n' 'Ваш,\nАлексей Дмитриев'
 
 Ваш,
 
 Алексей Дмитриев

А теперь вместо формата %b применим формат %q:

 $ printf '%q\n' 'Ваш,\nАлексей Дмитриев'
 
 $'\320\222\320\260\321\210,\\n\320\220\320\273\320\265\320\272\321\201\320\265\320\271   \320\224\320\274\320\270\321\202\321\200\320\270\320\265\320\262'

Кажется, произошла какая-то ошибка или сбой. Но это не так; подставим вывод команды в качестве аргумента команды printf '%b\n', но уже безо всяких дополнительных кавычек (все необходимые кавычки содержатся в выводе команды):

 $ printf '%b\n' $'\320\222\320\260\321\210,\\n\320\220\320\273\320\265\320\272\321\201\320\265\320\271   \320\224\320\274\320\270\321\202\321\200\320\270\320\265\320\262'
 
 Ваш,
 
 Алексей Дмитриев

Больше того, этот же вывод можно использовать в качестве аргумента для других команд, скажем echo -e (опция -e позволяет команде echo интерпретировать специальные символы, в частности символ новой строки (\n):

 $ echo -e $'\320\222\320\260\321\210, \\n\320\220\320\273\320\265\320\272\321\201\320\265\320\271   \320\224\320\274\320\270\321\202\321\200\320\270\320\265\320\262'
   
 Ваш,
 
 Алексей Дмитриев

Вот какой интересный формат %q! Однако продолжим.

Дальше идут всевозможные форматы представления чисел.

%d Представляет аргумент в виде десятичного числа, могущего иметь знак (+ или -).

%u Представляет аргумент в виде десятичного числа, не имеющего знака.

  $ printf '%d\n' -777
  
  -777

%i То же, что и предыдущее.

%o Представляет аргумент в виде не имеющего знака восьмеричного числа.

  $ printf '%o\n' 777
  
  1411

%x Представляет аргумент в виде не имеющего знака шестнадцатеричного числа. Буквы пишутся в нижнем регистре.

  $ printf '%x\n' 177
  
  b1

%X Представляет аргумент в виде не имеющего знака шестнадцатеричного числа, при этом буквы пишутся в верхнем регистре.

  $ printf '%X\n' 177
  
  B1

%f Интерпретирует аргумент как число с плавающей запятой.

  $ printf '%f\n' 17,7
  
  17,700000

%e Интерпретирует аргумент с удвоенной точностью (double precision), при этом выводит его в формате <N>+/-e<N>.

 $ printf '%e\n' 177
 
 1,770000e+02

%E То же, что и предыдущее, только с заглавной буквой Е.

Вот и все форматы, я привел их для встроенной в bash команды printf.

Модификаторы форматов

Для большей гибкости представления строк или чисел, поддерживаются несколько модификаторов форматов. Модификаторы вставляются между символом процента и буквой, характеризующей формат, например:

 [ya@antony ~]$ printf '%50s\n' 'this field is 50 characters wide...'
 
              this field is 50 characters wide...


(С кириллицей не работает).

Модификаторы: Любое число Обозначает минимальную ширину колонки, если текст короче, то строки дополняются пробелами. (См. пример выше).

  1. Альтернативный формат для чисел, см. ниже.

- Выравнивание текста по левому краю (стандарно - по правому краю)

0 Дополняет числа нулями, а не пробелами. Применяется при заданной ширине колонки (в примере 50). Пример:

 $ printf '%050d\n' '177'
 
 00000000000000000000000000000000000000000000000177

space Дополняет положительные числа пробелами, а отрицательные знаками "минус" (-).

+ Пишет все числа со знаками плюс или минус.

Альтернативный формат для чисел

%#o Восьмеричные числа пишутся с нулем впереди, если они сами не нулевые:

 $ printf '%#0o\n' '177'
 
 0261

%#x, %#X Шестнадцатеричные числа пишутся с или впереди, если они сами не нулевые:

 $ printf '%#x\n' '177'
 
 0xb1

%#g, %#G Числа с плавающей запятой пишутся с последующими нулями, в количестве, определяемом данным разрешением. Обычно последующие нули не пишутся:

 $ printf '%#g\n' '17,7'
 
 17,7000

%# со всеми числовыми форматами, кроме d, o, x, X Всегда ставит десятичную запятую, даже если знаков после запятой нет:

 $ printf '%#ge\n' '177'
 
 177,000

Точность разрешения

Точность разрешения чисел с плавающей запятой и чисел с удвоенной точностью (double precision) можно регулировать следующим образом:

 $ printf "%.20f\n" 4,3
 
 4,30000000000000000017

Внимание: не прозевайте точку в записи формата!

Можно вместо числа знаков поставить астериск, тогда количество знаков ставится перед самим аргументом:

 $ printf "%.*f\n" 10 4,3
 
 4,3000000000

Для строк точность разрешения определяет максимальное число выводимых символов (максимальную ширину колонки текста).

Для целых чисел - задает число выводимых знаков (добавляет нули).

Управляющие символы языка Си, работающие с командой printf

\" Двойные кавычки

\NNN Символ с восьмеричным значением NNN (от 1 до 3 цифр)

\\ Обратный слэш (\)

\a Звуковой сигнал

\b Забой

\c Не производить дальнейшую обработку данных

\f Перевод страницы

\n Новая строка

\r Возврат каретки

\v Вертикальная табуляция

\xHH Символ с шестнадцатеричным кодом HH (1 или 2 цифры)

\uHHHH Символ Unicode (ISO/IEC 10646) с шестнадцатеричным кодом HHHH (4 цифры)

\UHHHHHHHH Символ Unicode с шестнадцатеричным кодом HHHHHHHH (8 цифр)

%% Символ %

Еще несколько примеров

1. Вывести шестнадцатеричное число в десятичной форме:

 $ printf '%d\n' '-0x41'
 
 -65

2. Вывести десятичное число в восьмеричной форме:

 $ printf '%o\n' 65
 
 101

3. Узнать кодовый номер буквы А (англ):

 $ printf '%d\n' \'A
 
 65

4. Пример, служащий домашним заданием:

 $ printf '%b\n' "$0" "$@"
 
 /bin/bash

Кто понял, в чем тут дело, сообщите мне, пожалуйста. Я лично не понял.

Опции команды printf

Опция -v ПЕРЕМЕННАЯ_ОКРУЖЕНИЯ

Записывает аргумент в указанную переменную окружения. При этом затирает все, что там было прописано. Осторожно!

 $ printf -v PATH '%b\n' '/usr/local/bin'
 
 $ printf '%b\n' $PATH
 
 /usr/local/bin
 
 $ su
 
 bash: su: команда не найдена


Хорошо, что в начале статьи я привел пример, в котором была записана моя $PATH, поэтому смог восстановить.

Опции --help и --version общеизвестны и рассмотрены не будут.

Примечание: В мане GNU-версии команды вы не найдете и половины этой информации, а будете отосланы к синтаксису языка Си.

Резюме команды printf

Исследуя подобные команды, получаешь настоящее удовольствие, маны практически отсутствуют, найденные статьи относятся к другим версиям команды. Почти все приходится добывать методом эксперимента. Сколько еще удивительных особенностей таит команда printf, узнают только те, кто станет пользоваться ей в повседневной жизни.

Должен предупредить, что собрал в этой статье все, что сумел "нарыть" по поводу всех версий этой команды. Поэтому некоторые варианты могут не срабатывать в ваших версиях.

Ссылки

open-club.ru