Apple Developer Connection
Member Login Log In | Not a Member? Contact ADC

< Previous PageNext Page > Hide TOC

Shell Text Formatting

One powerful technique when writing shell scripts is to take advantage of the terminal emulation features of your terminal application (whether it is Terminal, an xterm, or some other application) to display formatted content.

You can use the printf command to easily create columnar layouts without any special tricks. For more visually exciting presentation, you can add color or text formatting such as boldface or underlined display using ANSI (VT100/VT220) escape sequences.

In addition, you can use ANSI escape sequences to show or hide the cursor, set the cursor position anywhere on the screen, and set various text attributes, including boldface, inverse, underline, and foreground and background color.

In this section:

Using the printf Command for Tabular Layout
Truncating Strings
Using ANSI Escape Sequences
ANSI Escape Sequence Tables


Using the printf Command for Tabular Layout

Much like C and other languages, most operating systems that support shell scripts also provide a command-line version of printf. This command differs from the C printf function in a number of ways. These differences include the following:

Much like the printf statement in other languages, the shell script printf syntax is as follows:

printf "format string" argument ...

Like the C printf function, the command-line printf format string contains some combination of text, switches (\n and \t, for example), and placeholders (%d, for example).

The most important feature of printf for tabular layouts is the padding feature. Between the percent sign and the type letter, you can place a number to indicate the width to which the field should be padded. For a floating-point placeholder (%f), you can optionally specify two numbers separated by a decimal point. The leftmost value indicates the total field width, while the rightmost value indicates the number of decimal places that should be included. For example, you can print pi to three digits of precision in an 8-character-wide field by typing printf "%8.3f" 3.14159265.

In addition to the width of the padding, you can add certain prefixes before the field width to indicate special padding requirements. They are:

For example, if you want to create a four-column table of name, address, phone number, and GPA, you might write a statement like this:

Listing 7-6  Columnar printing with printf

#/bin/sh
 
NAME="John Doe"
ADDRESS="1 Fictitious Rd, Bucksnort, TN"
PHONE="(555) 555-5555"
GPA="3.885"
printf "%20s | %30s | %14s | %5s\n" "Name" "Address" "Phone Number" "GPA"
printf "%20s | %30s | %14s | %5.2f\n" "$NAME" "$ADDRESS" "$PHONE" "$GPA"

The printf statement pads the fields into neat columns and truncates the GPA to two decimal places, leaving room for three additional characters (the decimal point itself, the ones place, and a leading space). You should notice that the additional arguments are all surrounded by quotation marks. If you do not do this, you will get incorrect behavior because of the spaces in the arguments.

Note: The printf command, like its C function sibling, does not truncate values to fit within the specified field width. For examples of how to truncate strings, see “Truncating Strings.”

The next sample shows number formatting:

#!/bin/sh
 
GPA="3.885"
 
printf "%f | whatever\n" "$GPA"
printf "%20f | whatever\n" "$GPA"
printf "%+20f | whatever\n" "$GPA"
printf "%+020f | whatever\n" "$GPA"
printf "%-20f | whatever\n" "$GPA"
printf "%- 20f | whatever\n" "$GPA"

This prints the following output:

3.885000 | whatever
            3.885000 | whatever
           +3.885000 | whatever
+000000000003.885000 | whatever
3.885000             | whatever
 3.885000            | whatever

Most of the same formatting options apply to %s and %d (including, surprisingly, zero-padding of string arguments). For more information, see the manual page for printf.

Truncating Strings

To truncate a value to a given width, you can use a simple regular expression to keep only the first few characters. For example, the following snippet copies the first seven characters of a string:

STRING="whatever you want it to be"
TRUNCSTRING="`echo "$STRING" | sed 's/^\(.......\).*$/\1/'`"
echo "$TRUNCSTRING"

As an alternative, you can use a more general-purpose routine such as the one in Listing 7-7, which truncates a string to an arbitrary length by building up a regular expression.

Listing 7-7  Truncating text to column width

function trunc_field()
{
    local STR=$1
    local CHARS=$2
    local EXP=""
    local COUNT=0
    while [ $COUNT -lt $CHARS ] ; do
        EXP="$EXP."
        COUNT=`expr $COUNT + 1`
    done
    echo $STR | sed "s/^\($EXP\).*$/\1/"
}

printf "%10s | something\n" "`trunc_field "$TEXT" 20`"

Of course, you can do this much faster by either caching these strings or replacing most of the function with a single line of Perl:

echo "$STR" | perl -e "$/=undef; print substr(<STDIN>, 0, $CHARS);"

Finally, if you are willing to write code that is extremely nonportable (using a syntax that does not even work in zsh), you can use Bash-specific substring expansion:

echo "${STR:0:8}"

You can learn about similar operations in the manual page for bash under the “Parameter Expansion” heading. As a general rule, however, you should avoid such shell-specific tricks.

Using ANSI Escape Sequences

You can use ANSI escape sequences to add color or formatting to text displayed in the terminal, reposition the cursor, set tab stops, clear portions of the display, change scrolling behavior, and more. This section includes a partial list of many commonly used escape sequences, along with examples of how to use them.

Important: For the purposes of this section, the Esc (escape) key is represented by the notation ^[ because the ASCII character for the Esc key is the same as the ASCII character for Control-bracket (character 27). Thus, when you see ^[[, it means Esc followed by a bracket. (Nearly all ANSI escape sequences begin with Esc-bracket, though there are a few exceptions.)

There are two ways to generate escape sequences: direct printing and using the terminfo database. Printing the sequences directly has significant performance advantages but is less portable because it assumes that all terminals are ANSI/VT100/VT220-compliant. A good compromise is to combine these two approaches by caching the values generated with a terminfo command such as tput at the beginning of your script and then printing the values directly elsewhere in the script.

Generating Escape Sequences using the terminfo Database

Generating escape sequences with the terminfo database is relatively straightforward once you know what terminal capabilities to request. You can find several tables containing capability information, along with the standard ANSI/VT220 values for each capability, in “ANSI Escape Sequence Tables.” (Note that not all ANSI escape sequences have equivalent terminfo capabilities, and vice versa.)

Once you know what capability to request (along with any additional arguments that you must specify), you can use the tput command to output the escape sequence (or capture the output of tput into a variable so you can use it later). For example, you can clear the screen with the following command:

tput cl

Some terminfo database entries contain placeholders for numeric values, such as row and column information. The easiest way to use these is to specify those numeric values on the command line when calling tput. However, for performance, it may be faster to substitute the values yourself. For example, the capability cup sets the cursor position to a row and column value. The following command sets the position to row 3, column 7:

tput cup 3 7

You can, however, obtain the unsubstituted string by requesting the capability without specifying row and column parameters. For example:

tput cup | less

By piping the data to less, you can see precisely what the tput tool is providing, and you can look up the parameters in the manual page for terminfo. This particular example prints the following string:

^[[%i%p1%d;%p2%dH

The %i notation means that the first two (and only the first two) values are one greater than you might otherwise expect. (For ANSI terminals, columns and rows number from 1 rather than from 0). The %p1%d means to push parameter 1 onto the stack and then print it immediately. The parameter %p2%d is the equivalent for parameter 2.

As you can see from even this relatively simple example, the language used for terminfo is quite complex. Thus, while it may be acceptable to perform the substitution for simple terminals such as VT100 yourself, you may still be trading performance for portability. In general, it is best to let tput perform the substitutions on your behalf.

Generating Escape Sequences Directly

To use an ANSI escape sequence without using tput, you must first be able to print an escape character from your script. There are three ways to do this:

Because the terminal reset command is one of only a handful of escape sequences that do not start with a left square bracket, it is worth pointing out the two sets of double-quote marks after the variable in the above example. Without those, the shell would try to print the value of the variable ESCc, which does not exist.

ANSI Escape Sequence Tables

There are four basic categories of escape codes:

Cursor and Scrolling Manipulation Escape Sequences

The terminal window is divided into a series of rows and columns. The upper-left corner is row 1, column 1. The lower-right corner varies depending on the size of the terminal window.

You can obtain the current number of rows and columns on the screen by examining the values of the shell variables LINES and COLUMNS. Thus, the screen coordinates range from (1, 1) to ($LINES, $COLUMNS). In most modern Bourne shells, the values for LINES and COLUMNS are automatically updated when the window size changes. This is true for both bash and zsh.

However, in bash, these variables are set only for interactive instances of the shell. This presents a small problem for shell scripts that care about window size. As a result, in versions of Mac OS X where the default shell is bash (Mac OS X v10.3 and newer), these variables are not defined in shell scripts that start with #!/bin/sh.

Of course, you could request zsh as the interpreter by changing the first line of your script to #!/bin/zsh, but this is not particularly portable. Fortunately, without changing shells, you can easily obtain the current row and column count with the code in Listing 7-8.

Listing 7-8  Obtaining terminal size using stty or tput

# If tput is available, this is the easy way:
MYLINES=`tput lines` # ROWS
MYCOLUMNS=`tput cols` # COLUMNS
 
# If not, you can do it the hard way.  This usually works.
MYLINES=`stty -a | grep rows | sed 's/^.*;\(.*\)rows\(.*\);.*$/\1\2/' | sed 's/;.*$//' | sed 's/[^0-9]//g'` # ROWS
MYCOLUMNS=`stty -a | grep columns | sed 's/^.*;\(.*\)columns\(.*\);.*$/\1\2/' | sed 's/;.*$//' | sed 's/[^0-9]//g'` # COLUMNS

If you want to be particularly clever, you can also trap the SIGWINCH signal and update your script’s notion of lines and columns when it occurs. See “Trapping Signals” for more information.

Once you know the number of rows and columns on your screen, you can move the cursor around with the escape sequences listed in Table 7-2. For example, to set the cursor position to row 4, column 5, you could issue the following command:

printf "\e[4;5H"

For other, faster ways to print escape sequences, see “Generating Escape Sequences Directly.”

Table 7-2  Cursor and scrolling manipulation escape sequences

Terminfo capability

Escape sequence

Description

tivis

Note: The terminfo entry for Terminal does not support this option.

^[[?25l

Hides the cursor.

tvvis

Note: The terminfo entry for Terminal does not support this option.

^[[?25h

Shows the cursor.

cup row colum

^[[r;cH

Sets cursor position to row r, column c.

(no equivalent)

^[[6n

Reports current cursor position as though typed from the keyboard (reported as ^[[r;cR). Note: it is not practical to capture this information in a shell script.

sc

^[7

Saves current cursor position and style.

rc

^[8

Restores previously saved cursor position and style.

cuu r

^[[rA

Moves cursor up r rows.

cud r

^[[rB

Moves cursor down r rows.

cuf c

^[[cC

Moves cursor right c columns.

cub c

^[[cD

Moves cursor left c columns.

(no equivalent)

^[[7h

Disables automatic line wrapping when the cursor reaches the right edge of the screen.

(no equivalent)

^[[7l

Enables line wrapping (on by default).

(no equivalent)

^[[r

Enables whole-screen scrolling (on by default).

(no equivalent)

^[[S;Er

Enables partial-screen scrolling from row S to row E and moves the cursor to the top of this region.

do

^[D

Moves the cursor down by one line.

up

^[M

Moves the cursor up by one line.

Attribute and Color Escape Sequences

Attribute and color escape sequences allow you to change the attributes or color for text that you have not yet drawn. No escape sequence (scrolling notwithstanding) changes anything that has already been drawn on the screen. Escape sequences apply only to subsequent text.

For example, to draw a red “W” character, first send the escape sequence to set the foreground color to red (^[[31m), then print a “W” character, then send an attribute reset sequence (^[[m), if desired.

The attribute and color escape codes can be combined with other attribute and color escape codes in the form ^[[#;#;#;...#m. For example, you can combine the escape sequences ^[[1m (bold) and ^[[32m green text) into the sequence ^[[1;32m. Listing 7-9 prints a familiar phrase in multiple colors.

Listing 7-9  Using ANSI color

#!/bin/sh
 
printf '\e[41mH\e[42me\e[43ml\e[44;32ml\e[45mo\e[m \e[46;33m'
printf 'W\e[47;30mo\e[40;37mr\e[49;39ml\e[41md\e[42m!\e[m\n'

Note: For consistent formatting, you may add a leading zero to any single-digit attribute escape sequences, if desired. For example, ^[[1m is equivalent to ^[[01m.

Table 7-3 contains a list of capabilities and escape sequences that control text style.

Table 7-3  Attribute escape sequences

Terminfo capability

Escape sequence

Description

Resetting attributes

me

^[[m or ^[[0m

Resets all attributes to their default values.

Setting attributes

bold

^[[1m

Enables “bright” display. This is basically boldface text. This code and code #2 (dim) are mutually exclusive.

dim

^[[2m

Enables “dim” display. This code and code #1 (bold) are mutually exclusive. Not supported in Terminal.

so

Note: In the terminfo database entry for Terminal, this is mapped to inverse because the VT100 “standout” mode is not supported.

^[[3m

Enables “standout” display. Not supported in Terminal.

us

^[[4m

Enables underlined display.

blink

Note: The terminfo entry for Terminal does not support this option.

^[[5m

<blink>.

(No equivalent.)

^[[6m

Fast blink or strike-through. (Not supported in Terminal; behavior inconsistent elsewhere.)

mr

^[[7m

Enables reversed (inverse) display.

invis

Note: The terminfo entry for Terminal does not support this option.

^[[8m

Enables hidden (background-on-background) display.

^[[9m

Unused.

Codes 10m19m

Font selection codes. Unsupported in most terminal applications, including Terminal.

Clearing attributes

(No equivalent.)

^[[20m

“Fraktur” typeface. Unsupported almost universally, and Terminal is no exception.

^[[21m

Unused.

se

Note: Technically, this capability is supposed to end standout mode, but it is overloaded to disable bold bright/dim mode as well.

^[[22m

Disables “bright” or “dim” display. This disables either code 1m or 2m.

se

^[[23m

Disables “standout” display. Not supported in Terminal.

ue

^[[24m

Disables underlined display.

(No equivalent. Use me to disable all attributes instead.)

^[[25m

</blink>. Also disables slow blink or strike-through (6m) on terminals that support that attribute.

^[[26m

Unused.

(No equivalent. Use me to disable all attributes instead.)

^[[27m

Disables reversed (inverse) display.

(No equivalent. Use me to disable all attributes instead.)

^[[28m

Disables hidden (background-on-background) display.

^[[29m

Unused.

Table 7-4 contains a list of capabilities and escape sequences that control text and background colors.

Table 7-4  Color escape sequences

Terminfo capability

Escape sequence

Description

Foreground colors

setaf 0

^[[30m

Sets foreground color to black.

setaf 1

^[[31m

Sets foreground color to red.

setaf 2

^[[32m

Sets foreground color to green.

setaf 3

^[[33m

Sets foreground color to yellow.

setaf 4

^[[34m

Sets foreground color to blue.

setaf 5

^[[35m

Sets foreground color to magenta.

setaf 6

^[[36m

Sets foreground color to cyan.

setaf 7

^[[37m

Sets foreground color to white.

^[[38m

Unused.

setaf 9

^[[39m

Sets foreground color to the default.

Background colors

setab 0

^[[40m

Sets background color to black.

setab 1

^[[41m

Sets background color to red.

setab 2

^[[42m

Sets background color to green.

setab 3

^[[43m

Sets background color to yellow.

setab 4

^[[44m

Sets background color to blue.

setab 5

^[[45m

Sets background color to magenta.

setab 6

^[[46m

Sets background color to cyan.

setab 7

^[[47m

Sets background color to white.

^[[48m

Unused.

setab 9

^[[49m

Sets background color to the default.

Other Escape Sequences

In addition to providing text formatting, ANSi escape sequences provide the ability to reset the terminal, clear the screen (or portions thereof), clear a line (or portions thereof), and set or clear tab stops.

For example, to clear all existing tab stops and set a single tab stop at column 20, you could use the snippet show in Listing 7-10.

Listing 7-10  Setting tab stops

#!/bin/sh
echo # Start on a new line
printf "\e[19C" # move right 19 columns to column 20
printf "\e[3g" # clear all tab stops
printf "\e[W" # set a new tab stop
printf "\e[19D" # move back to the left
printf "Tab test\tThis starts at column 20."

Table 7-5 contains a list of capabilities and escape sequences that perform other miscellaneous tasks such as cursor control, tab stop manipulation, and clearing the screen or portions thereof.

Table 7-5  Other escape codes

Terminfo capability

Escape sequence

Description

Resetting the terminal

reset

Note: This resets many more things than ^[c. It is also technically not a single capability but rather the contatenation of rs1, rs2, and rs3.

^[c

Resets the background and foreground colors to their default values, clears the screen, and moves the cursor to the home position.

Clearing the screen

cd

^[[J or ^[[0J

Clears to the bottom of the screen using the current background color.

(no equivalent)

^[[1J

Clears to the top of the screen using the current background color.

cl

^[[2J

Clears the screen to the current background color. On some terminals, the cursor is reset to the home position.

Clearing the current line

ce

^[[K or ^[[0K

Clears to the end of the current line.

cb—Not supported in terminfo entry for Terminal.

^[[1K

Clears to the beginning of the current line.

(no equivalent)

^[[2K

Clears the current line.

Tab stops

hts

^[[W or ^[[0W

Set horizontal tab at cursor position.

(no equivalent)

^[[1W

Set vertical tab at current line. (Not supported in Terminal.)

Codes 2W6W

Redundant codes equivalent to codes 0g3g.

(no equivalent)

^[[g or ^[[0g

Clear horizontal tab at cursor position.

(no equivalent)

^[[1g

Clear vertical tab at current line. (Not supported in Terminal.)

(no equivalent)

^[[2g

Clear horizontal and vertical tab stops for current line only. (Not supported in Terminal.)

tbc

^[[3g

Clear all horizontal tabs.

Note: You can also set tab stops with the command-line utility tabs.

For More Information

The tables in this chapter provide only some of the more commonly used escape sequences and terminfo capabilities. You can find an exhaustive list of ANSI escape sequences at http://www.inwap.com/pdp10/ansicode.txt and an exhaustive list of terminfo capabilities in the manual page for terminfo.

Before using capabilities or escape sequences not in this chapter, however, you should be aware that most terminal software (including Terminal in Mac OS X) does not support the complete set of ANSI escape sequences or terminfo capabilities.



< Previous PageNext Page > Hide TOC


Last updated: 2008-04-08




Did this document help you?
Yes: Tell us what works for you.

It’s good, but: Report typos, inaccuracies, and so forth.

It wasn’t helpful: Tell us what would have helped.
Get information on Apple products.
Visit the Apple Store online or at retail locations.
1-800-MY-APPLE

Copyright © 2007 Apple Inc.
All rights reserved. | Terms of use | Privacy Notice