This show has been flagged as Clean by the host.
This series is dedicated to exploring little-known—and occasionally useful—trinkets lurking in the dusty corners of UNIX-like operating systems.
The
echo
command is very useful—it prints the arguments given to it, followed by a newline character. (The newline is sometimes also called a linefeed character depending on who is writing or speaking, and has the ASCII decimal value 10.) It has many uses, either in a script or interactively on the command line. The
echo
utility is used to display text, the value of a variable, or the result of a pathname 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
2
—although the manual page doesn't explicitly say output is followed by a newline character, the description of writing "as a line" seems to imply it. In
6
.
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 (%d, %i, %o, %u, %x, %X, %c, and %s, plus %b and %% described below).
Two more conversion specifications are worth mentioning. The first is
only
required by the standard for the
printf
utility, not the C function, and is "%b". This is the same as "%s", except that certain backslash escape sequences in the argument 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 "\0" followed by one to three octal digits. An additional backslash escape sequence accepted is "\c"—this does not print anything itself, but causes
printf
to immediately halt output.
The final conversion specification is "%%", which just outputs a literal "%". You can't use a bare "%" in the format string, because
printf
expects that to introduce a conversion specification. Be careful not to be tripped up by this when trying to print some value as a percentage.
Example assuming that the hypothetical "/dev/batterycharge" file on your laptop outputs the battery charge level (42% in this case). As you can see, in some cases an error message might be displayed, but in others it might just behave in a way you didn't intend without complaining. GNU's "printf" utility and the "printf" builtin of bash both support "%e" as a conversion specification as an extension to POSIX.
$ cat /dev/batterycharge
42
$ #Wrong
$ printf "Your laptop's charge level is $(cat /dev/batterycharge)%.\n"
bash: printf: `\': invalid format character
Your laptop's charge level is 42$ #Shell prompt appears here from the error
$ #Right
$ printf "Your laptop's charge level is $(cat /dev/batterycharge)%%.\n"
Your laptop's charge level is 42%.
$ #Next one treats %e as the specifier, with the space and "l" as flags
$ printf "Your laptop has $(cat /dev/batterycharge)% level of charge.\n"
Your laptop has 42 0.000000e+00vel of charge.
$ #Because no arguments were given, "0" was used for the value to convert
Let's go back to the situation I was describing with
echo
—we have files named "-n" and "something" in the current directory and want to print all their names, separated by spaces. We could do that with
printf "%s " *
, which would not treat the "-n" as an option. However, the output might look a little weird because there wouldn't be a newline character at the end. We could insert a newline by using "%b" instead of "%s" and following the asterisk with a "\n\c" as the second argument. The "\c" is there to prevent the final space in the format string from being printed after the newline.
$ ls -1
-n
something
$ printf "%s " *
-n something $ #No newline was printed here
$ printf "%b " * "\n"
-n something
$ #There's a newline, but also a spurious space before the shell prompt
$ printf "%b " * "\n\c"
-n something
$ #No space before the shell prompt this time
Using the "%b" conversion specification can therefore solve one problem, but it also introduces another. Arguments which include a backslash can be interpreted as escape sequences, and many systems are fine with allowing backslashes in filenames. 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 create security problems if processed by a script or utility running as a privileged user.
$ #GNU "ls" displays filenames containing a backslash in single quotes
$ ls -1
apple
banana
'\cherry'
durian
$ printf "%b " * "\n\c"
apple banana $ #"\c" in "\cherry" stops output immediately
The
printf
utility
8
is from the Tenth Edition. Its first appearance in BSD
10
and where the first character is
not
a hyphen. This set includes the lowercase and uppercase letters "a" through "z", 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
https://archive.org/details/a_research_unix_reader/page/n99/mode/1up
https://man.cat-v.org/unix_7th/1/echo
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html
https://archive.org/details/a_research_unix_reader/page/n95/mode/1up
https://man.freebsd.org/cgi/man.cgi?query=printf&sektion=1&manpath=4.3BSD+Reno
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/pathchk.html
Provide feedback on this episode.
SOCIAL SHARE CARD GENERATOR