如何在Bash中对齐表格列?

use*_*294 65 bash echo

我想输出一个表格格式文本.我试图做的是使用'\ t'回显数组的元素,但它未对齐.我的代码

for((i=0;i<array_size;i++));
do
   echo stringarray[$i] $'\t' numberarray[$i] $'\t' anotherfieldarray[$i]
done;
Run Code Online (Sandbox Code Playgroud)

我的输出

a very long string..........     112232432      anotherfield
a smaller string         123124343     anotherfield
Run Code Online (Sandbox Code Playgroud)

期望的输出

a very long string..........     112232432      anotherfield
a smaller string                 123124343      anotherfield
Run Code Online (Sandbox Code Playgroud)

P.P*_*.P. 120

使用列命令:

column -t -s' ' filename
Run Code Online (Sandbox Code Playgroud)

  • @BurhanAli 我需要重复我之前的评论吗?所有答案都假设有一些分隔符。OP 没有提到分隔符。因此,相同的分隔符也可以在列中使用。*由于数据的第一列中有空格*那么如何将其称为*第一*列? (3认同)
  • 准备分隔符的示例: `sed -r 's/\s+/ /g' /etc/fstab | 列-t -s''` (3认同)
  • 准备分隔符的示例:`cat / etc / fstab | sed -r's / \ s + / / g'| 列-t -s''` (2认同)

Uta*_*ead 71

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
Run Code Online (Sandbox Code Playgroud)

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

man 1 printf 了解更多信息.

  • 只有一个建议在打印表时很有用:`%-10s` wiil生成长度为10的左对齐字符串 (27认同)
  • @UtahJarhead 对变量 stringarray[$i] 的引用应替换为 ${stringarray[i]} ,并且第一个字符串空格必须用引号引起来“${stringarray[i]}”以避免空格字符被解释为分隔符。 (2认同)

Gil*_*not 14

要获得所需的完全相同的输出,您需要格式化文件:

a very long string..........\t     112232432\t     anotherfield\n
a smaller string\t      123124343\t     anotherfield\n
Run Code Online (Sandbox Code Playgroud)

然后使用:

$ column -t -s $'\t' FILE
a very long string..........  112232432  anotherfield
a smaller string              123124343  anotherfield
Run Code Online (Sandbox Code Playgroud)

  • `$'\t'` 中的 `$` 是做什么的? (3认同)

Nam*_*yen 14

function printTable()
{
    local -r delimiter="${1}"
    local -r data="$(removeEmptyLines "${2}")"

    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(" ", "-", $0)}1'
            fi
        fi
    fi
}

function removeEmptyLines()
{
    local -r content="${1}"

    echo -e "${content}" | sed '/^\s*$/d'
}

function repeatString()
{
    local -r string="${1}"
    local -r numberToRepeat="${2}"

    if [[ "${string}" != '' && "${numberToRepeat}" =~ ^[1-9][0-9]*$ ]]
    then
        local -r result="$(printf "%${numberToRepeat}s")"
        echo -e "${result// /${string}}"
    fi
}

function isEmptyString()
{
    local -r string="${1}"

    if [[ "$(trimString "${string}")" = '' ]]
    then
        echo 'true' && return 0
    fi

    echo 'false' && return 1
}

function trimString()
{
    local -r string="${1}"

    sed 's,^[[:blank:]]*,,' <<< "${string}" | sed 's,[[:blank:]]*$,,'
}
Run Code Online (Sandbox Code Playgroud)

样品运行

$ 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  |
+---------+
Run Code Online (Sandbox Code Playgroud)

REF LIB位于:https : //github.com/gdbtek/linux-cookbooks/blob/master/libraries/util.bash

  • 小心!参考链接有更多更新的功能。 (2认同)

小智 6

这比你想象的要容易。

如果您也使用分号分隔的文件和标题:

$ (head -n1 file.csv && sort file.csv | grep -v <header>) | column -s";" -t
Run Code Online (Sandbox Code Playgroud)

如果您正在使用数组(使用制表符作为分隔符):

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
Run Code Online (Sandbox Code Playgroud)