Рейтинг@Mail.ru
[Войти] [Зарегистрироваться]

Наши друзья и партнеры

UnixForum
Беспроводные выключатели nooLite

Lines Club

Ищем достойных соперников.


Книги по Linux (с отзывами читателей)

Библиотека сайта или "Мой Linux Documentation Project"

На главную -> MyLDP -> Тематический каталог -> Работа в консоли Linux

HuMan: printf

Алексей Дмитриев, 20 сентября 2009

Команда printf выводит АРГУМЕНТ на стандартный вывод (как правило, экран дисплея), используя при этом определенный ФОРМАТ.

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

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

Возможности команды echo ограничены, кроме того, в разных ветках Unix'а оказались разные ее версии, что приводит к несовместимости.

Поэтому Posix рекомендует пользоваться командой printf.

Самое первое, что следует прояснить: по умолчанию команда 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 Представляет аргумент в виде десятичного числа, могущего иметь знак (+ или -).
$ printf '%d\n' -777
-777
%u Представляет аргумент в виде десятичного числа, не имеющего знака.

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

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

Модификаторы:

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

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

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

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

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

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

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

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

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

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

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

$ 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, узнают только те, кто станет пользоваться ей в повседневной жизни.

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


Все статьи серии HuMan


Средняя оценка 5 при 1 голосовавших
Вы сможете оценить статью и оставить комментарий, если войдете или зарегистрируетесь.
Только зарегистрированные пользователи могут оценивать и комментировать статьи.

Комментарии

Олег Безначев пишет: 26.09.2009
по поводу $ printf '%b\n' "$0" "$@" дак $ echo $0 bash у вас видимо /bin/bash А echo $@

Александр Лидин пишет: 28.09.2009
printf - команда языков семейства С, и здесь она немного отличается, большинство можно было "нарыть", почитав литературу по С.