如何在 Bash 中对齐表格的列?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12768907/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I align the columns of tables in Bash?
提问by user1709294
I'd like to output a table format text. What I tried to do was echo the elements of an array with '\t', but it was misaligned.
我想输出表格格式文本。我试图做的是用 '\t' 回显数组的元素,但它没有对齐。
My code
我的代码
for((i=0;i<array_size;i++));
do
echo stringarray[$i] $'\t' numberarray[$i] $'\t' anotherfieldarray[$i]
done;
My output
我的输出
a very long string.......... 112232432 anotherfield
a smaller string 123124343 anotherfield
Desired output
期望输出
a very long string.......... 112232432 anotherfield
a smaller string 123124343 anotherfield
回答by P.P
Use column command:
使用列命令:
column -t -s' ' filename
回答by UtahJarhead
printf
is great, but people forget about it.
printf
很棒,但人们忘记了它。
$ for num in 1 10 100 1000 10000 100000 1000000; do printf "%10s %s\n" $num "foobar"; done
1 foobar
10 foobar
100 foobar
1000 foobar
10000 foobar
100000 foobar
1000000 foobar
$ for((i=0;i<array_size;i++));
do
printf "%10s %10d %10s" stringarray[$i] numberarray[$i] anotherfieldarray[%i]
done
Notice I used %10s
for strings. %s
is the important part. It tells it to use a string. The 10
in the middle says how many columns it is to be. %d
is for numerics (digits).
注意我用于%10s
字符串。 %s
是重要的部分。它告诉它使用一个字符串。在10
中间说,这是多少列是。 %d
用于数字(数字)。
man 1 printf
for more info.
man 1 printf
了解更多信息。
回答by Nam Nguyen
function printTable()
{
local -r delimiter=""
local -r data="$(removeEmptyLines "")"
if [[ "${delimiter}" != '' && "$(isEmptyString "${data}")" = 'false' ]]
then
local -r numberOfLines="$(wc -l <<< "${data}")"
if [[ "${numberOfLines}" -gt '0' ]]
then
local table=''
local i=1
for ((i = 1; i <= "${numberOfLines}"; i = i + 1))
do
local line=''
line="$(sed "${i}q;d" <<< "${data}")"
local numberOfColumns='0'
numberOfColumns="$(awk -F "${delimiter}" '{print NF}' <<< "${line}")"
# Add Line Delimiter
if [[ "${i}" -eq '1' ]]
then
table="${table}$(printf '%s#+' "$(repeatString '#+' "${numberOfColumns}")")"
fi
# Add Header Or Body
table="${table}\n"
local j=1
for ((j = 1; j <= "${numberOfColumns}"; j = j + 1))
do
table="${table}$(printf '#| %s' "$(cut -d "${delimiter}" -f "${j}" <<< "${line}")")"
done
table="${table}#|\n"
# Add Line Delimiter
if [[ "${i}" -eq '1' ]] || [[ "${numberOfLines}" -gt '1' && "${i}" -eq "${numberOfLines}" ]]
then
table="${table}$(printf '%s#+' "$(repeatString '#+' "${numberOfColumns}")")"
fi
done
if [[ "$(isEmptyString "${table}")" = 'false' ]]
then
echo -e "${table}" | column -s '#' -t | awk '/^\+/{gsub(" ", "-", $ cat data-1.txt
HEADER 1,HEADER 2,HEADER 3
$ printTable ',' "$(cat data-1.txt)"
+-----------+-----------+-----------+
| HEADER 1 | HEADER 2 | HEADER 3 |
+-----------+-----------+-----------+
$ cat data-2.txt
HEADER 1,HEADER 2,HEADER 3
data 1,data 2,data 3
$ printTable ',' "$(cat data-2.txt)"
+-----------+-----------+-----------+
| HEADER 1 | HEADER 2 | HEADER 3 |
+-----------+-----------+-----------+
| data 1 | data 2 | data 3 |
+-----------+-----------+-----------+
$ cat data-3.txt
HEADER 1,HEADER 2,HEADER 3
data 1,data 2,data 3
data 4,data 5,data 6
$ printTable ',' "$(cat data-3.txt)"
+-----------+-----------+-----------+
| HEADER 1 | HEADER 2 | HEADER 3 |
+-----------+-----------+-----------+
| data 1 | data 2 | data 3 |
| data 4 | data 5 | data 6 |
+-----------+-----------+-----------+
$ cat data-4.txt
HEADER
data
$ printTable ',' "$(cat data-4.txt)"
+---------+
| HEADER |
+---------+
| data |
+---------+
$ cat data-5.txt
HEADER
data 1
data 2
$ printTable ',' "$(cat data-5.txt)"
+---------+
| HEADER |
+---------+
| data 1 |
| data 2 |
+---------+
)}1'
fi
fi
fi
}
function removeEmptyLines()
{
local -r content=""
echo -e "${content}" | sed '/^\s*$/d'
}
function repeatString()
{
local -r string=""
local -r numberToRepeat=""
if [[ "${string}" != '' && "${numberToRepeat}" =~ ^[1-9][0-9]*$ ]]
then
local -r result="$(printf "%${numberToRepeat}s")"
echo -e "${result// /${string}}"
fi
}
function isEmptyString()
{
local -r string=""
if [[ "$(trimString "${string}")" = '' ]]
then
echo 'true' && return 0
fi
echo 'false' && return 1
}
function trimString()
{
local -r string=""
sed 's,^[[:blank:]]*,,' <<< "${string}" | sed 's,[[:blank:]]*$,,'
}
SAMPLE RUNS
样品运行
a very long string..........\t 112232432\t anotherfield\n
a smaller string\t 123124343\t anotherfield\n
REF LIB at: https://github.com/gdbtek/linux-cookbooks/blob/master/libraries/util.bash
REF LIB 在:https: //github.com/gdbtek/linux-cookbooks/blob/master/libraries/util.bash
回答by Gilles Quenot
To have the exact same output as you need, you need to format the file like that :
要获得与您需要的完全相同的输出,您需要像这样格式化文件:
$ column -t -s $'\t' FILE
a very long string.......... 112232432 anotherfield
a smaller string 123124343 anotherfield
And then using :
然后使用:
$ (head -n1 file.csv && sort file.csv | grep -v <header>) | column -s";" -t
回答by Renan Benedicto Pereira
It's easier than you wonder.
这比你想象的要容易。
If you are working with a separated by semicolon file and header too:
如果您也使用分号分隔的文件和标题:
for((i=0;i<array_size;i++));
do
echo stringarray[$i] $'\t' numberarray[$i] $'\t' anotherfieldarray[$i] >> tmp_file.csv
done;
cat file.csv | column -t
If you are working with array (using tab as separator):
如果您正在使用数组(使用制表符作为分隔符):
stringarray=('test' 'some thing' 'very long long long string' 'blah')
numberarray=(1 22 7777 8888888888)
anotherfieldarray=('other' 'mixed' 456 'data')
array_size=4
for((i=0;i<array_size;i++))
do
echo ${stringarray[$i]} $'\x1d' ${numberarray[$i]} $'\x1d' ${anotherfieldarray[$i]}
done | column -t -s$'\x1d'
回答by Benubird
Not sure where you were running this, but the code you posted would not produce the output you gave, at least not in the bash that I'm familiar with.
不确定您在哪里运行它,但是您发布的代码不会产生您提供的输出,至少在我熟悉的 bash 中不会。
Try this instead:
试试这个:
$output = $tablePrinter->printLinesIntoArray($items, ['title', 'chilProp2']);
Note that I'm using the group seperator character (1d) intead of tab, because if you are getting these arrays from a file, they might contain tabs.
请注意,我使用的是组分隔符 (1d) 而不是制表符,因为如果您从文件中获取这些数组,它们可能包含制表符。
回答by redestructa
Just in case someone wants to do that in PHP I posted a gist on Github
以防万一有人想在 PHP 中做到这一点,我在 Github 上发布了一个要点
https://gist.github.com/redestructa/2a7691e7f3ae69ec5161220c99e2d1b3
https://gist.github.com/redestructa/2a7691e7f3ae69ec5161220c99e2d1b3
simply call:
只需调用:
stringarray[0]="a very long string.........."
# 28Char (max length for this column)
numberarray[0]=1122324333
# 10digits (max length for this column)
anotherfield[0]="anotherfield"
# 12Char (max length for this column)
stringarray[1]="a smaller string....."
numberarray[1]=123124343
anotherfield[1]="anotherfield"
printf "%30s %10d %13s" "${stringarray[0]}" ${numberarray[0]} "${anotherfield[0]}"
printf "\n"
printf "%30s %10d %13s" "${stringarray[1]}" ${numberarray[1]} "${anotherfield[1]}"
# a var string with spaces has to be quoted
printf "\n Next line will fail \n"
printf "%30s %10d %13s" ${stringarray[0]} ${numberarray[0]} "${anotherfield[0]}"
a very long string.......... 1122324333 anotherfield
a smaller string..... 123124343 anotherfield
you may need to adapt the code if you are using a php version older than 7.2
如果您使用的是低于 7.2 的 php 版本,则可能需要修改代码
after that call echo or writeLine depending on your environment.
之后根据您的环境调用 echo 或 writeLine 。
回答by Daniel Perez
Below code has been tested and does exactly what is requested in the original question.
下面的代码已经过测试,并且完全符合原始问题中的要求。
Parameters: %30s Column of 30 char and text right align. %10d integer notation, %10s will also work. Added clarification included on code comments.
参数:%30s 30 个字符的列和文本右对齐。%10d 整数表示法,%10s 也可以使用。添加了包含在代码注释中的说明。
##代码##