web-dev-qa-db-fra.com

Comment aligner les colonnes de tables dans Bash?

Je voudrais sortir un texte sous forme de tableau. Ce que j'ai essayé de faire était de faire écho aux éléments d'un tableau avec '\ t'

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

Ma sortie

a very long string..........     112232432      anotherfield
a smaller string         123124343     anotherfield

Sortie désirée

a very long string..........     112232432      anotherfield
a smaller string                 123124343      anotherfield
43
user1709294

printf c'est bien, mais les gens l'oublient.

$ 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

Notez que j'ai utilisé %10s pour les chaînes. %s est la partie importante. Il lui dit d'utiliser une chaîne. Le 10 au milieu indique le nombre de colonnes. %d est pour numérique (chiffres).

man 1 printf pour plus d'informations.

56
UtahJarhead

Utiliser la commande de colonne:

column -t -s' ' filename
100
P.P.

Pour obtenir exactement le même résultat que vous avez besoin, vous devez formater le fichier comme suit:

a very long string..........\t     112232432\t     anotherfield\n
a smaller string\t      123124343\t     anotherfield\n

Et puis en utilisant:

$ column -t -s $'\t' FILE
a very long string..........  112232432  anotherfield
a smaller string              123124343  anotherfield
10
Gilles Quenot

Vous ne savez pas trop où vous avez exécuté cela, mais le code que vous avez publié ne produira pas le résultat que vous avez donné, du moins pas lors de la bash que je connais bien.

Essayez ceci à la place:

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'

Notez que j'utilise le caractère séparateur de groupe (1d) au lieu d'un onglet, car si vous obtenez ces tableaux à partir d'un fichier, ils peuvent contenir des onglets.

3
Benubird
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:]]*$,,'
}

ÉCHANTILLONS

$ 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  |
+---------+

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

3
Nam Nguyen

C'est plus facile que vous vous le demandez.

Si vous utilisez également un fichier séparé par point-virgule et un en-tête:

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

Si vous travaillez avec array (en utilisant tab comme séparateur):

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
1

awk solution qui traite stdin

Puisque column n'est pas POSIX, c'est peut-être:

mycolumn() (
  file="${1:--}"
  if [ "$file" = - ]; then
    file="$(mktemp)"
    cat >"${file}"
  fi
  awk '
  FNR == 1 { if (NR == FNR) next }
  NR == FNR {
    for (i = 1; i <= NF; i++) {
      l = length($i)
      if (w[i] < l)
        w[i] = l
    }
    next
  }
  {
    for (i = 1; i <= NF; i++)
      printf "%*s", w[i] + (i > 1 ? 1 : 0), $i
    print ""
  }
  ' "$file" "$file"
  if [ "$file" = - ]; then
    rm "$file"
  fi
)

Tester:

printf '12 1234 1
12345678 1 123
1234 123456 123456
' > file

Commandes de test:

mycolumn file
mycolumn <file
mycolumn - <file

Sortie pour tous:

      12   1234      1
12345678      1    123
    1234 123456 123456

Voir également:

Juste au cas où quelqu'un voudrait faire cela dans PHP, j'ai posté un Gist sur Github.

https://Gist.github.com/redestructa/2a7691e7f3ae69ec5161220c99e2d1b3

appelez simplement:

$output = $tablePrinter->printLinesIntoArray($items, ['title', 'chilProp2']);

vous devrez peut-être adapter le code si vous utilisez une version de PHP supérieure à 7.2.

après cet appel, echo ou writeLine en fonction de votre environnement.

0
redestructa