pr

Paginate or columnate FILE(s) for printing.

As stated in the above quote from the manual, the pr command is mainly used for those two tasks. This book will discuss only the columnate features and some miscellaneous tasks.

Here's a pagination example if you are interested in exploring further. The pr command will add blank lines, a header and so on to make it suitable for printing.

$ pr greeting.txt | head


2021-08-05 14:10                   greeting.txt                   Page 1


Hi there
Have a nice day



Columnate

The --columns and -a options can be used to merge the input lines in two different ways:

  • split the input file and then merge them as columns
  • merge consecutive lines, similar to the paste command

Here's an example to get started. Note that -N is same as using --columns=N where N is the number of columns you want in the output. The default page width is 72, which means each column can only have a maximum of 72/N characters (including the separator). Tab and space characters will be used to fill the columns as needed. You can use the -J option to prevent pr from truncating longer columns. The -t option is used here to turn off the pagination features.

# split input into three parts
# each column width is 72/3 = 24 characters max
$ seq 9 | pr -3t
1                       4                       7
2                       5                       8
3                       6                       9

You can customize the separator using the -s option. The default is a tab character which you can change to any other string value. The -s option also turns off line truncation, so -J option isn't needed. However, the default page width of 72 can still cause issues, which will be discussed later.

# tab separator
$ seq 9 | pr -3ts
1       4       7
2       5       8
3       6       9

# comma separator
$ seq 9 | pr -3ts,
1,4,7
2,5,8
3,6,9

# multicharacter separator
$ seq 9 | pr -3ts' : '
1 : 4 : 7
2 : 5 : 8
3 : 6 : 9

Use the -a option to merge consecutive lines, similar to the paste command. One advantage is that the -s option supports a string value, whereas with paste you'd need to use workarounds to get multicharacter separation.

# four consecutive lines are merged
# same as: paste -d: - - - -
$ seq 8 | pr -4ats:
1:2:3:4
5:6:7:8

There are other differences between the pr and paste commands as well. Unlike paste, the pr command doesn't add the separator if the last row doesn't have enough columns. Another difference is that pr doesn't support an option to use the NUL character as the line separator.

$ seq 10 | pr -4ats,
1,2,3,4
5,6,7,8
9,10

$ seq 10 | paste -d, - - - -
1,2,3,4
5,6,7,8
9,10,,

Customizing page width

As mentioned before, the default page width is 72. This can cause lines to be truncated, unless -s or -J options are used. There's another issue you might run into, for example:

$ seq 100 | pr -50ats,
pr: page width too narrow

(N-1)*length(separator) + N is the minimum page width you need, where N is the number of columns required. So, for 50 columns and a separator of length 1, you'll need a minimum width of 99. This calculation doesn't make any assumption about the size of input lines, so you may need -J to ensure input lines aren't truncated.

You can use the -w option to change the page width. The -w option overrides the effect of -s option on line truncation, so use -J option as well unless you really need truncation. If truncation is active, maximum column width is (PageWidth - (N-1)*length(separator)) / N rounded down to an integer value. Here's some examples:

# minimum width needed is 3 for N=2 and length=1
# maximum column width: (6 - 1) / 2 = 2
$ pr -w6 -2ts, greeting.txt
Hi,Ha
# use -J to avoid truncation
$ pr -J -w6 -2ts, greeting.txt
Hi there,Have a nice day

# N=3 and length=4, so minimum width needed is (3-1)*4 + 3 = 11
$ seq 6 | pr -J -w10 -3ats'::::'
pr: page width too narrow
$ seq 6 | pr -J -w11 -3ats'::::'
1::::2::::3
4::::5::::6

# you can also use a large number to avoid having to calculate the width
$ seq 6 | pr -J -w500 -3ats'::::'
1::::2::::3
4::::5::::6

Concatenating files column wise

Two or more input files can be merged column wise using the -m option. As seen before, -t is needed to ignore pagination features and -s can be used to customize the separator.

# same as: paste colors_1.txt colors_2.txt
$ pr -mts colors_1.txt colors_2.txt
Blue    Black
Brown   Blue
Orange  Green
Purple  Orange
Red     Pink
Teal    Red
White   White

# same as: paste -d' : ' <(seq 3) /dev/null /dev/null <(seq 4 6)
$ pr -mts' : ' <(seq 3) <(seq 4 6)
1 : 4
2 : 5
3 : 6

You can prefix the output with line numbers using the -n option. By default, this option supports up to 5 digit numbers and uses the tab character to separate the numbering and line contents. You can optionally pass two arguments to this option — maximum number of digits and the separator character. If both arguments are used, the separator should be specified first. If you want to customize the starting line number, use the -N option as well.

# maximum of 1 digit for numbering
# use : as the separator between line number and line contents
$ pr -n:1 -mts, colors_1.txt colors_2.txt
1:Blue,Black
2:Brown,Blue
3:Orange,Green
4:Purple,Orange
5:Red,Pink
6:Teal,Red
7:White,White

The string passed to -s is treated literally. Depending on your shell you can use ANSI-C quoting to allow escape sequences. Unlike columnate, the separator is added even if the data is missing for some of the files.

# greeting.txt has 2 lines
# fruits.txt has 3 lines
# same as: paste -d$'\n' greeting.txt fruits.txt
$ pr -mts$'\n' greeting.txt fruits.txt
Hi there
banana
Have a nice day
papaya

mango

Miscellaneous

You can use the -d option to double space the input contents. That is, every newline character is doubled.

$ pr -dt fruits.txt
banana

papaya

mango

The -v option will convert non-printing characters like carriage return, backspace, etc to their octal representations (\NNN).

$ printf 'car\bt\r\nbike\0p\r\n' | pr -vt
car\010t\015
bike\000p\015

pr -t is a roundabout way of concatenating input files. But one advantage is that this will add a newline character at the end if not present in the input.

# 'cat' will not add a newline character
# so, use 'pr' if newline is needed at the end
$ printf 'a\nb\nc' | pr -t
a
b
c