如何在 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 22:48:30  来源:igfitidea点击:

How can I align the columns of tables in Bash?

bashecho

提问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

printfis 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 %10sfor strings. %sis the important part. It tells it to use a string. The 10in the middle says how many columns it is to be. %dis for numerics (digits).

注意我用于%10s字符串。 %s是重要的部分。它告诉它使用一个字符串。在10中间说,这是多少列是。 %d用于数字(数字)。

man 1 printffor 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 也可以使用。添加了包含在代码注释中的说明。

##代码##