Home / Alt manpages / column(1)

  • column(1)
  • User command
  • linux

Turn Messy Command Output into Reliable Tables with column

You will use column to turn whitespace- or delimiter-separated input into readable columns, then build a named table with predictable alignment. The examples also show how to avoid the two defaults that cause most surprises: columns are filled before rows, and empty input fields are normally treated differently from missing fields.

Allow about ten minutes. You need a shell and the bsdextrautils package on this Ubuntu machine. The installed executable reports util-linux 2.41.3; the local manual page is labelled util-linux 2.39.3, so verify unusual behaviour against the command on the host where a script will run. These examples only read input and write standard output. They do not need sudo.

1. Arrange a simple list

Give column one item per line. With no options, it reads standard input and fills columns before rows:

$ printf '%s\n' pear apple banana kiwi | column
pear    apple   banana  kiwi

The exact gaps depend on the item widths and available output width. Empty lines are ignored by default. A file can be supplied instead of the pipe:

$ column /path/to/items.txt

Checkpoint: run column --version. On this machine it prints column from util-linux 2.41.3. If your output differs, keep the input small and compare the local column(1) manual before putting the command in a script.

2. Choose row-first filling when reading across is clearer

--fillrows, also written -x, fills each row before starting the next column. It is useful for short menus or labels where the reader should scan left to right:

$ printf '%s\n' pear apple banana kiwi | column --fillrows --output-width 20
pear    apple
banana  kiwi

The width option makes the example reproducible. Without it, an interactive terminal supplies its width, while non-interactive output defaults to 80 columns. Output longer than a requested width is not truncated unless you request truncation in table mode.

3. Build a named table from records

Use --table when each input line contains fields. Add --table-columns to name the fields and create the header. Do not include a header line in the input unless you deliberately want that line displayed as data:

$ printf '%s\n' 'root 20G online' 'var 8G full' |
  column --table --table-columns NAME,SIZE,STATE --table-right SIZE
NAME  SIZE  STATE
root   20G  online
var     8G  full

--table-right SIZE right-aligns the named column. The default output separator is two spaces. To use a visible separator, set --output-separator:

$ printf '%s\n' 'root 20G online' 'var 8G full' |
  column --table --table-columns NAME,SIZE,STATE --table-right SIZE \
  --output-separator ' | '
NAME | SIZE | STATE
root | 20G  | online
var  | 8G   | full

The backslash continues the shell command; it is not part of the data. Keep field names free of spaces because they are a comma-separated option argument.

4. Parse a delimiter without destroying empty fields

For input separated by a known character, use --separator or -s. This example keeps the empty middle field between the two colons:

$ printf '%s\n' 'root:20G:online' 'var::full' |
  column --table --separator ':' --output-separator ' | '
root | 20G | online
var  |     | full

In table mode without explicit names, the command uses the input's fields but does not invent a header. The installed command treats -s as a non-greedy separator, as documented since util-linux 2.23. That matters when two delimiters are adjacent: do not replace this test with a whitespace pipeline and assume the empty value will survive.

Checkpoint: inspect the rendered line for var. There should be a blank field between the two output separators. If a later tool needs to distinguish blank from absent data, test that tool separately; visual alignment alone is not a data-quality check.

5. Control width and decide whether truncation is safe

Use --output-width or -c when output goes to a terminal, log or fixture with a known width. The manual recommends unlimited (or 0) when writing to files so the table is not constrained by an accidental terminal size:

$ printf '%s\n' 'root 20G online' 'var 8G full' |
  column --table --table-columns NAME,SIZE,STATE --output-width unlimited \
  > /tmp/storage-table.txt
$ sed -n '1,4p' /tmp/storage-table.txt
NAME  SIZE  STATE
root  20G   online
var   8G    full

Redirecting to /tmp is ordinary user work. The file is temporary and may be removed by system cleanup. If a long cell must fit a fixed display, use --table-truncate with the relevant column, but treat the result as presentation only:

$ printf '%s\n' 'alice short' 'bob very-long-description' |
  column --table --output-width 20 --table-truncate 2
name   description
alice  short
bob    very-long-des

Do not truncate identifiers, paths or values that another command will parse. A shorter display is not a shorter value.

6. Export a table as JSON when names are available

--json requires --table-columns. Supply --table-name as well when the JSON key should be explicit:

$ printf '%s\n' 'alpha 7' 'beta 9' |
  column --json --table --table-columns name,count --table-name items
{
   "items": [
      {
         "name": "alpha",
         "count": "7"
      },{
         "name": "beta",
         "count": "9"
      }
   ]
}

The values are strings unless you define a column with a json=number or json=boolean attribute using --table-column. JSON output is a format conversion, not validation: check that the source fields are in the expected order and that blank values are acceptable to the consumer.

7. Print a tree from parent and child IDs

For records with an ID, a parent ID and a label, use --tree-id, --tree-parent and --tree. Column numbers are one-based:

$ printf '%s\n' '1 0 root' '2 1 child' '3 1 other' '4 2 leaf' |
  column --tree-id 1 --tree-parent 2 --tree 3
1  0  root
2  1  ├─child
4  2  │ └─leaf
3  1  └─other

The tree is an output view of the relationships. Circular dependencies and other anomalies are silently ignored according to the manual, so do not use a successful display as proof that the input graph is valid. Validate IDs and parent references separately when the data matters.

Common mistakes and safe recovery

If a header appears twice, remove the header from the input or stop supplying --table-columns; the option itself creates the named header. If fields shift, check the real delimiter and quote your separator argument. If a line disappears, remember that empty lines are ignored unless you add --keep-empty-lines or -L.

Do not overwrite a useful report blindly with shell redirection. The > operator truncates its destination before column runs. Write to a new temporary path, inspect it, then replace the old file only if that replacement is intentional:

$ column --table --table-columns NAME,SIZE,STATE /path/to/input.txt > /tmp/report.new
$ test -s /tmp/report.new && mv /tmp/report.new /path/to/report.txt

If the command fails, the old report is untouched. Remove the temporary file with rm /tmp/report.new only after checking its exact path; that deletion cannot be undone through column.

Done means

  • You can arrange a list and choose column-first or row-first filling deliberately.
  • You can name table columns, align numeric-looking fields and choose an output separator.
  • You preserve delimiter-separated empty fields and know that whitespace parsing is a different case.
  • You set output width explicitly when reproducibility matters, and truncate only display-safe fields.
  • You use JSON and tree output only after checking the input field order and relationships.
  • You write replacement reports to a new path before moving them into place.