Existe-t-il une commande simple permettant d’afficher des colonnes délimitées par des tabulations?

67

Par exemple, j'ai un fichier (produit avec echo -e "var1\tvar2\t\var3\tvar4" > foo) qui est sorti en tant que:

$ cat foo
case    elems   meshing nlsys
uniform 2350    0.076662        2.78
non-conformal   348     0.013332        0.55
scale   318     0.013333        0.44
smarter 504     0.016666        0.64
submodel        360     .009999 0.40
unstruct-quad   640     0.019999        0.80
unstruct-tri    1484    0.01    0.88

Je préférerais la sortie comme ceci (ici j'ai utilisé vimet :set tabstop=14):

case          elems         meshing       nlsys
uniform       2350          0.076662      2.78
non-conformal 348           0.013332      0.55
scale         318           0.013333      0.44
smarter       504           0.016666      0.64
submodel      360           .009999       0.40
unstruct-quad 640           0.019999      0.80
unstruct-tri  1484          0.01          0.88

Je peux obtenir la même fonctionnalité catsi j'utilise $ tabs=15bash (voir cette question ). Y at-il un programme qui fait ce genre de formatage automatiquement? Je ne veux pas expérimenter avec la tabsvaleur avant de catcréer un fichier.

Sébastien
la source

Réponses:

87

J'utilise habituellement le columnprogramme pour cela, c'est dans un paquet appelé bsdmainutilsDebian:

column -t foo

Sortie:

case           elems  meshing   nlsys
uniform        2350   0.076662  2.78
non-conformal  348    0.013332  0.55
scale          318    0.013333  0.44
smarter        504    0.016666  0.64
submodel       360    .009999   0.40
unstruct-quad  640    0.019999  0.80
unstruct-tri   1484   0.01      0.88

Extrait de column(1)mon système:

...

-t      Determine the number of columns the input contains and create a
        table.  Columns are delimited with whitespace, by default, or
        with the characters supplied using the -s option.  Useful for
        pretty-printing displays.

...
Thor
la source
génial! Merci beaucoup! Il était déjà installé sur ma machine.
Sébastien
11
vous souhaiterez peut-être ajouter le -s $'\t'(non trouvé dans toutes les implémentations de colonnes) au cas où certains champs contiennent des espaces.
Stéphane Chazelas
2
@RakholiyaJenish $'\t'signifie tabulation. La nouvelle ligne est $'\n'et ainsi de suite.
Manwe
2
Je l'ai utilisé comme column -ts: /etc/passwd. Ça a l'air cool!
kyb
1
@kyb: semble encore mieux avec -n, c'est-à-dire éviter de fusionner plusieurs délimiteurs adjacents
Thor
10

Plusieurs options:

var1=uniform var2=2350 var3=0.076662 var4=2.78

printf '%-15s %-10s %-12s %s\n' \
  case elems messing nlsys \
  "$var1" "$var2" "$var3" "$var4"

printf '%s\t%s\t%s\t%s\n' \
  case elems messing nlsys \
  "$var1" "$var2" "$var3" "$var4" |
  expand -t 15,25,37

printf '%s\t%s\t%s\t%s\n' \
  case elems messing nlsys \
  "$var1" "$var2" "$var3" "$var4" |
  column -t -s $'\t'

column est une commande non standard, certaines implémentations / versions ne supportent pas l'option -s. Il calcule la largeur de la colonne en fonction de l'entrée, mais cela signifie qu'il ne peut commencer à afficher que lorsque toute l'entrée a été alimentée. $'...'La syntaxe ksh93 est également trouvée dans zsh et bash.

Avec zsh:

values=(
  case elems messing nlsys
  "$var1" "$var2" "$var3" "$var4"
)
print -arC4 -- "$values[@]"
Stéphane Chazelas
la source
4

Vous pouvez également utiliser rsune alternative à column -t:

(x=$(cat);rs -c -z $(wc -l<<<"$x")<<<"$x")

-cmodifie le séparateur de colonne d'entrée, mais -cseul définit le séparateur de colonne d'entrée sur un onglet. -zdéfinit la largeur de chaque colonne sur la largeur de l'entrée la plus longue de la colonne au lieu de faire en sorte que toutes les colonnes aient la même largeur. Si certaines lignes ont moins de colonnes que la première, ajoutez -n.

nisetama
la source
Qui rsest-ce? Je n'ai pas installé cette commande sur mon CentOS ni sur mes systèmes Ubuntu / Mint.
Anthon
1
@ Anthony Il s'agit d'une commande BSD fournie avec OS X, nommée d'après la fonction de remodelage dans APL. Le nom du paquet Debian est juste rs, vous pouvez donc l’installer avec apt-get install rs.
nisetama
Pourriez-vous donner un exemple de la façon dont on appelle la commande (x=$(cat);rs -c -z $(wc -l<<<"$x")<<<"$x")? Je ne sais pas comment utiliser un fichier csv
baxx
3

Un autre outil qui peut le faire est celui tsv-prettyde TSV Utilities d' eBay (disclaimer: je suis l'auteur). Il faut l'étape supplémentaire consistant à aligner les champs numériques sur le point décimal. Par exemple:

$ tsv-pretty foo
case           elems   meshing  nlsys
uniform         2350  0.076662   2.78
non-conformal    348  0.013332   0.55
scale            318  0.013333   0.44
smarter          504  0.016666   0.64
submodel         360   .009999   0.40
unstruct-quad    640  0.019999   0.80
unstruct-tri    1484  0.01       0.88

Il existe plusieurs options de formatage. Par exemple, -usouligne l’en-tête et -fformate les flottants dans un champ de manière similaire pour des raisons de lisibilité:

$ tsv-pretty foo -f -u
case           elems   meshing  nlsys
----           -----   -------  -----
uniform         2350  0.076662   2.78
non-conformal    348  0.013332   0.55
scale            318  0.013333   0.44
smarter          504  0.016666   0.64
submodel         360  0.009999   0.40
unstruct-quad    640  0.019999   0.80
unstruct-tri    1484  0.010000   0.88

Plus d'informations sont disponibles dans la référence tsv-pretty .

JonDeg
la source
C'est vraiment utile
Arefe
1

La question portait sur la sortie des colonnes délimitées par des tabulations.

La réponse correcte est donc une petite adaptation de la réponse de @nisetama. J'ai ajouté l'option -C $ '\ t' qui définit le formatage de la sortie.

x=$(cat foo2); rs -C$'\t' $(wc -l <<<"$x") <<<"$x"

Bravo à @nisetama cependant :)

thehpi
la source
1
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

Nam Nguyen
la source
Intéressante solution bash-only - merci pour le partage
Sebastian
C'est trop compliqué. Et ce n'est pas uniquement bash car il y a des commandes externes comme sedêtre utilisé.
Codeforester