How can I format the output of a bash command in neat columns
I have a function which outputs many rows of information which I want to format in columns. The problem is that th开发者_如何转开发e width of any particular "cell" (if I may use that term) of data is variable, so piping it to something like awk does not give me what I want.
The function is "keys" (not that it matters) and I'm trying something like this:
$ keys | awk '{ print $1"\t\t" $2 }'
but the output (a snippet of it, that is) looks like this:
"option-y" yank-pop
"option-z" execute-last-named-cmd
"option-|" vi-goto-column
"option-~" _bash_complete-word
"option-control-?" backward-kill-word
"control-_" undo
"control-?" backward-delete-char
How can I force things to stay in neat columns? Is this possible with awk, or do I need to use something else?
column(1)
is your friend.
$ column -t <<< '"option-y" yank-pop
> "option-z" execute-last-named-cmd
> "option-|" vi-goto-column
> "option-~" _bash_complete-word
> "option-control-?" backward-kill-word
> "control-_" undo
> "control-?" backward-delete-char
> '
"option-y" yank-pop
"option-z" execute-last-named-cmd
"option-|" vi-goto-column
"option-~" _bash_complete-word
"option-control-?" backward-kill-word
"control-_" undo
"control-?" backward-delete-char
Found this by searching for "linux output formatted columns": Formatting output in columns
For your needs, it's like:
awk '{ printf "%-20s %-40s\n", $1, $2}'
While awk
's printf
can be used, you may want to look into pr
or (on BSDish systems) rs
for formatting.
Since AIX doesn't have a "column" command, I created the simplistic script below. It would be even shorter without the doc & input edits... :)
#!/usr/bin/perl
# column.pl: convert STDIN to multiple columns on STDOUT
# Usage: column.pl column-width number-of-columns file...
#
$width = shift;
($width ne '') or die "must give column-width and number-of-columns\n";
$columns = shift;
($columns ne '') or die "must give number-of-columns\n";
($x = $width) =~ s/[^0-9]//g;
($x eq $width) or die "invalid column-width: $width\n";
($x = $columns) =~ s/[^0-9]//g;
($x eq $columns) or die "invalid number-of-columns: $columns\n";
$w = $width * -1; $c = $columns;
while (<>) {
chomp;
if ( $c-- > 1 ) {
printf "%${w}s", $_;
next;
}
$c = $columns;
printf "%${w}s\n", $_;
}
print "\n";
Try
xargs -n2 printf "%-20s%s\n"
or even
xargs printf "%-20s%s\n"
if input is not very large.
If your output is delimited by tabs a quick solution would be to use the tabs
command to adjust the size of your tabs.
tabs 20
keys | awk '{ print $1"\t\t" $2 }'
You can try a function ie. in this case the following breaks up the declared arrays into two columns. $1 is then passed to this script as an arbitrary column width ie. 20. The function spaces () can then be used anywhere additional columns are required.
#!/bin/bash
WI="${1}"
# function
spaces () {
for (( a=0; a<(( $2 - $1 )); a++ )); do echo -n " "; done
}
# logic
declare -a NUMBERS=(One Two Three Four Five Six Seven)
declare -a DAYS=(Monday Tue Wednesday Thursday Friday Sat Sun)
for i in {0..6}
do
echo " ${NUMBERS[$i]}$(spaces ${#NUMBERS[$i]} ${WI})${DAYS[$i]}"
done
In your case you could use mapfile to populate the array MAPFILE presuming the file keys contains the un-formatted text. And then iterate through the array using spaces() to format the columns to the correct width.
#!/bin/bash
# function
spaces () {
for (( a=0; a<(( $2 - $1 )); a++ )); do echo -n " "; done
}
# logic
mapfile -t < keys
for line in "${MAPFILE[@]}"; do
LINE1=$(echo $line | awk '{print $1}')
LINE2=$(echo $line | awk '{print $2}')
echo " ${LINE1}$(spaces ${#LINE1} $1)${LINE2}"
done
exit
精彩评论