Refreshed episodes/hosts/comments/series from hpr.sql, and added official HPR transcripts for the 180 episodes aired since the last sync (hpr4516-hpr4695).
199 lines
13 KiB
Plaintext
199 lines
13 KiB
Plaintext
Episode: 4667
|
|
Title: UNIX Curio #9 - printf
|
|
Source: https://hub.hackerpublicradio.org/ccdn.php?filename=/eps/hpr4667/hpr4667.mp3
|
|
Transcribed: 2026-07-31 16:16:16 (official HPR transcript)
|
|
|
|
---
|
|
|
|
This is Hacker Public Radio Episode 4667, for 2026-06-23
|
|
Today's show is entitled, "UNIX Curio #9 - printf"
|
|
The host is Vance and the duration is 00:20:39
|
|
The flag is Clean, and the license is CC-BY-SA
|
|
The summary is "Displaying text without the echo"
|
|
Hi there, I'm Phance and welcome to Unix Curio number nine.
|
|
This series is dedicated to exploring little known and occasionally useful, trinkets lurking
|
|
in the dusty corners of Unix-like operating systems.
|
|
Instead of having an echo, why don't we talk about the echo utility a little bit?
|
|
The echo command is very useful.
|
|
It prints the arguments given to it, followed by a new line character.
|
|
The new line is sometimes also called a line feed character, depending on who is writing
|
|
or speaking, and it has the ASCII decimal value 10.
|
|
Also has many uses either in a script or interactively on the command line.
|
|
This utility can be used to display text, the value of variable, or the result of a path
|
|
name expansion.
|
|
It can also feed text to another command in a pipeline.
|
|
As useful as echo is, it should come as no surprise that it first appeared early on
|
|
in Bell Laboratories' second edition Unix in 1972.
|
|
This initial version accepted no options.
|
|
Although the manual page doesn't explicitly say output is followed by a new line character,
|
|
the description of writing as a line seems to imply it.
|
|
In seventh edition Unix, the manual page makes that clear and also features the addition
|
|
of the hyphen and option that's November in the phonetic alphabet, which causes echo
|
|
to print the arguments without a trailing new line character.
|
|
Eight edition Unix's echo gained the hyphen E option.
|
|
Coincidentally, that's echo in the phonetic alphabet, which allows the use of certain
|
|
escape codes from the C programming language to be used.
|
|
These variations cause differences in behavior between different versions of echo.
|
|
We'll running echo, hyphen N, something on your system, output the text, something without
|
|
a new line, or the text, hyphen N something followed by a new line.
|
|
These get even trickier when the command arguments include parameter or pass name expansions.
|
|
If there are files named hyphen N and something in the current directory, what does echo
|
|
asterisk output?
|
|
Like the previous question, that depends on whether or not your version of echo treats hyphen
|
|
N as an option.
|
|
You can't get around this ambiguity by quoting or escaping the asterisk because that
|
|
just causes echo to print a literal asterisk.
|
|
The solution was to create a new utility, which is the first Unix Curio for today, print
|
|
F.
|
|
This command allows a user to print text similar to the way the identically named function
|
|
works in the C programming language.
|
|
You run print F followed by a format string followed by zero or more arguments.
|
|
No new line characters are printed unless specifically indicated by the format string or
|
|
the arguments.
|
|
To use print F to print the word something without a new line, that would just be print
|
|
F something.
|
|
This demonstrates that you don't need any arguments.
|
|
In this example, the format string is just a set of regular characters to be displayed.
|
|
If you wanted a new line character at the end, print F double quote something backslash
|
|
n double quote would give you that.
|
|
In this case, the format string needs to be quoted so the backslash n isn't interpreted
|
|
by the shell.
|
|
In addition to backslash n for a new line, you can also use backslash a for an alert, which
|
|
rings the terminal bell, backslash b for a backspace, backslash f for a form feed, backslash
|
|
r for a carriage return, backslash t for a horizontal tab, backslash v for a vertical tab,
|
|
and backslash backslash to get a literal backslash.
|
|
In addition to these special characters, any arbitrary bite can be included using a backslash
|
|
followed by one to three octal digits.
|
|
However, it might be difficult to predict what will be output because it can differ
|
|
based on the character set the terminal is using.
|
|
It is safer and more portable to stick to the predefined characters if possible.
|
|
The real magic of the print F utility comes from using conversion specifications in the
|
|
format string.
|
|
Probably the simplest of these to explain is the percent sign S conversion specification.
|
|
It represents a string of any length.
|
|
The command print F double-quote high percent sign S, how are you backslash n double-quote followed
|
|
by a list of names as arguments would print the greeting on a separate line for each name,
|
|
putting it in the place occupied by the percent sign S.
|
|
The format string is reused as many times as needed to consume all of the arguments.
|
|
Take for example the command print F double-quote high percent sign S, have you met percent
|
|
sign S, backslash n double-quote?
|
|
If this is run with two name arguments, it would print the sentence on one line using both
|
|
names.
|
|
If run with four name arguments, it would print the sentence twice once with the first two names
|
|
and again with the second two names.
|
|
If you only gave it three names, the last percent sign S conversion specification would
|
|
be replaced with a null string.
|
|
Three other items can also be given in each conversion specification.
|
|
Flags the field width and the precision.
|
|
The exact meanings of these depend on which type of conversion specifier character you
|
|
are using.
|
|
For percent sign S, using a hyphen as the flag causes the text to be left justified instead
|
|
of the default right justified.
|
|
A field width causes the printed field to be at least as long as the number given and
|
|
a precision limits the number of bytes written from the string to the number given.
|
|
Some examples to illustrate these are included in these shown notes.
|
|
While percent sign S is probably the most commonly used conversion specification, others
|
|
are available.
|
|
A whole set of them are dedicated to printing integer values as a sign decimal and unsigned
|
|
decimal and unsigned octal or an unsigned hexadecimal number.
|
|
These can also take flags a field width and a precision.
|
|
I think the details and nuances of all this are two complex to clearly explain here, so
|
|
I will just refer you to the POSIX file format notation specification linked in the
|
|
shown notes.
|
|
Be aware that unlike the printf function in the C programming language, the printf utility
|
|
is not obligated to accept conversion specifications for floating point numbers.
|
|
While some implementations might support this, scripts intended to be portable, should
|
|
limit themselves to the restricted set required by the POSIX standard.
|
|
To more conversion specifications are worth mentioning, the first is only required by the standard
|
|
for the printf utility, not the C function and is percent sign B.
|
|
This is the same as percent sign S, except that certain backslash escape sequences in the
|
|
arguments will be treated specially.
|
|
This includes all the ones described above, except for the one using octal digits to represent
|
|
a byte.
|
|
In an argument, this is instead represented by backslash 0 followed by one to three octal digits.
|
|
An additional backslash escape sequence accepted is backslash C.
|
|
This does not print anything itself, but causes printf to immediately halt output.
|
|
The final conversion specification is percent sign percent sign, which just outputs a literal
|
|
percent sign.
|
|
You can't use a bare percent sign in the format string because printf expects that to introduce
|
|
a conversion specification.
|
|
Be careful not to get tripped up by this when trying to print some value as a percentage.
|
|
Let's go back to the situation I was describing with echo.
|
|
We have files named hyphen n and something in the current directory and want to print all
|
|
their names separated by spaces.
|
|
We could do that with printf double quote, percent sign S, space double quote, space
|
|
asterisk, which would not treat the hyphen n as an option.
|
|
However, the output might look a little weird because there wouldn't be a new line character
|
|
at the end.
|
|
We could insert that new line by using percent sign B instead of percent sign S and following
|
|
the asterisk with a second argument, backslash n backslash C as noted before that would
|
|
have to be quoted to prevent the shell from interpreting the backslashes.
|
|
The backslash C is there to prevent the final space in the format string from being printed
|
|
after the new line.
|
|
Using the percent sign B conversion specification can therefore solve one problem but it also
|
|
introduces another.
|
|
Since which include a backslash can be interpreted as escape sequences and many systems
|
|
are fine with allowing backslashes in file names.
|
|
I've included an example of this in the show notes.
|
|
In cases where you're just using the printf utility to display text, it's usually not a big
|
|
deal if the output looks a little wonky.
|
|
Where you really need to be careful is when the text is being piped to another program
|
|
as control characters and other oddities might cause unexpected results.
|
|
And can potentially even create security problems if processed by a script or utility running
|
|
as a privileged user.
|
|
The printf utility looks to have shown up first in 1986's 9th edition Unix, though
|
|
the earliest manual page I could find is from the 10th edition.
|
|
Its first appearance in BSD seems to be from 1990 in the 4.3 Reno release.
|
|
Two years later it was added to issue 4 of the open groups CIE specification.
|
|
From what I can tell the printf utility did not seem to be in AT&T's system 3.
|
|
Presumably it did make it into system 5 at some point but I found it difficult to track
|
|
this down.
|
|
While echo is still suitable for use where you know for certain that you want a new line
|
|
character printed at the end and none of the arguments will start with a hyphen, consider
|
|
using the printf utility instead for displaying text.
|
|
It offers more flexibility and features than you are guaranteed to get with echo, although
|
|
it does require a bit of forethought in constructing a proper format string and arguments.
|
|
That is not necessarily a bad thing because a script's author should be thinking about what
|
|
might happen if it is called with quote strange unquote text or file names.
|
|
This episode also provides a good case for being careful when naming files.
|
|
Many file systems will allow you to use hyphens, control characters, quotation marks and
|
|
potentially any character other than a slash or a null byte in a file name.
|
|
As we've seen some of these characters can create problems for standard utilities.
|
|
While it can feel limiting, especially for people not using English, the safest file
|
|
names to use on a unix-like system consists only of characters in the portable file name
|
|
character set as defined by posics and where the first character is not a hyphen.
|
|
This set includes the lower case and upper case letters a through Z or Z as some people pronounce
|
|
it.
|
|
The numerals 0 through 9 and the period underscore and hyphen, notably it does not include
|
|
the space character.
|
|
That leads me to another unix-curio that I only just now discovered while researching
|
|
this episode.
|
|
This is the path check utility spelled PA THCHK or in the phonetic alphabet Papa Alpha
|
|
Tango Hotel Charlie Hotel Kilo.
|
|
It can be run with one or more strings as arguments, checks each one against a set of rules
|
|
for path names and outputs an error message for each problem found.
|
|
By default, it checks against the following limits on the system where it's being run.
|
|
There are some number of bytes in the full path, maximum number of bytes in any component
|
|
of the path, all byte sequences must be valid in the given directory and the user running
|
|
the program must have access to all directories referenced.
|
|
If run with the hyphen lower case P option, that's Papa in the phonetic alphabet, instead
|
|
of those limits, it checks against POSIX limits, a maximum of 256 bytes in the full path,
|
|
a maximum of 14 bytes in each component of the path, and each component must only include
|
|
characters from the portable set.
|
|
The hyphen uppercase P option adds warnings if any component starts with a hyphen or if
|
|
the path name is completely empty.
|
|
While the exit status will tell you if the check succeeded or not, I don't feel like the
|
|
path check utility is well suited to be used in an automated fashion.
|
|
As the exact wording of its output is not specified, and checks cannot be selected individually.
|
|
However, it can be used interactively to validate path names you aren't sure about.
|
|
See the linked specification in these show notes for full details.
|
|
Thanks for listening, and keep an eye out for the next Unix Curio, which will be about
|
|
check sums here on hacker public radio.
|
|
If you have a question or a suggestion for a future topic, please comment on this episode
|
|
on the HPR website.
|
|
You have been listening to the Hacker Public Radio podcast, at hackerpublicradio.org.
|
|
Today's show was contributed by a HPR listener like yourself.
|
|
If you ever thought of recording a podcast, then visit the HPR site to find out how easy it really is.
|
|
Hosting for HPR has been kindly provided by anhonesthost.com, the Internet Archive, rsync.net, and the HPR Community Content Delivery Network.
|
|
Unless otherwise stated, today's show is released under a Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.
|