How to output an array's content in columns in BASH
I wanted to display a long list of strings from an array.
Right now, my script run through a for loop echoing each value to the standard output:
for value in ${values[@]}
do
echo $value
done
Yeah, that's pretty ugly! And the one column listing is pretty long too...
I was wondering if i can find a command or builtin helping me to d开发者_StackOverflow中文版isplay all those values in columns, like the ls
command does by default when listing a directory (ls -C
).
[Update]
Losing my brain with column
not displaying properly formatted columns, here's more info:
The values:
$ values=( 01----7 02----7 03-----8 04----7 05-----8 06-----8 07-----8 08-----8 09---6 10----7 11----7 12----7 13----7 14-----8 15-----8 16----7 17----7 18---6 19-----8 20-----8 21-----8)
Notice the first two digits as an index and the last one indicating the string length for readability.
The command: echo " ${values[@]/%/$'\n'}" | column
The result: bad columns http://tychostudios.ch/multipurpose/bad_columns.png
Something is going wrong...
You could pipe your output to column
.
column
seems to struggle with some data in a single-column input being narrower than a tabstop (8 characters).
Using printf
within a for
-loop to pad values to 8 characters seems to do the trick:
for value in "${values[@]}"; do
printf "%-8s\n" "${value}"
done | column
Here are a couple of techniques that can be used with Johnsyweb's answer so you can do your output without a loop:
saveIFS=$IFS
IFS=$'\n'
echo "${values[*]}" | column
IFS=$saveIFS
or
echo " ${arr[@]/%/$'\n'}" | column
or
echo " ${arr[@]/%/$'\n'}" | sed 's/^ //' | column
I know this is an old thread, but I get erratic results from column so I thought I'd give my solution. I wanted to group every 3 lines into 3 evenly spaced columns.
cat file.txt | xargs printf '%-24s\n' | sed '$p;N;s/\n//;$p;N;s/\n//'
Basically, it pipes each line into printf, which left-aligns it into a 24-character-wide block of whitespace, which is then piped into sed. sed will look ahead 2 lines into the future and remove the line break.
The N command reads the next line into the current buffer, and s/\n// removes the line break. In short, what we want is 'N;N;s/\n//g', which will work in some cases. The problem is, if there aren't two extra lines to throw in the buffer, sed will quit suddenly. The $p commands pre-empt that by saying "If this is the last line, print the buffer contents immediately".
It may look overkill, but i came up with my own solution. I wrote a little script that does exactly what i wanted: take a list of values and output them in a pretty formatted column view.
http://github.com/Arko/Columnize
For some reason column
doesn't work for me. In my case I have an array like
$ array = ( 1 2 3 dir1 dir2 dir3 )
$
$ echo ${array[@]} | column
1 2 3 dir1 dir2 dir3
instead I used
$ echo ${array[@]} | tr ' ' '\n' | sort
1
2
3
dir1
dir2
dir3
I know it's an old thread but I ran into this same situation. I ended up combining a few ideas from here.
For the column utility based solution (without initial space issue):
(IFS=''; echo "${values[*]/%/$'\n'}") | column
Using @Arko's script for basis, this can handle values with spaces. Notice the printf spec of %-*s for left justified colums and right would drop the '-'. I didn't include my terminal guessing but it is settable (terminalWidth).
# e.g. column "$@"
# spacing=4 column "$@"
# left=6 spacing=3 column "$@"
#
function column() {
local leftMargin=${left:-0}
local padding=${spacing:-2}
local maxWidth=$(( ${terminalWidth:-80} - $leftMargin ))
local values=("$@")
local max=$(( $(IFS=''; echo "${values[*]/%/$'\n'}" | wc -L) + $padding ))
local cols=$(( $maxWidth / $max ))
local pos=0 NL=''
for value in "${values[@]}"; do
[[ $pos == 0 ]] && {
printf "$NL%*s" "$leftMargin"
NL=$'\n' # add newlines from now on...
}
printf "%-*s" "$max" "$value"
(( pos = ($pos + 1) % $cols ))
done
echo
}
Tabspaces
Use a tab after each value.
( It automatically flows to next line too... )
for value in ${values[@]}
do
echo -en "$value\t"
done
Detailed info here
GoodLUCK!!
- CVS
精彩评论