Gibt es einen einfachen Befehl zur Ausgabe von tabulatorgetrennten Spalten?

67

ZB habe ich eine Datei (produziert mit echo -e "var1\tvar2\t\var3\tvar4" > foo), die ausgegeben wird als:

$ 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

Ich würde die Ausgabe wie folgt bevorzugen (hier habe ich vimund verwendet :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

Ich kann die gleiche Funktionalität erhalten, catwenn ich $ tabs=15in Bash verwende (siehe diese Frage ). Gibt es ein Programm, das diese Art der Formatierung automatisch durchführt? Ich möchte tabsvor dem catErstellen einer Datei nicht mit dem Wert experimentieren .

Sebastian
quelle

Antworten:

87

Ich benutze normalerweise das columnProgramm dafür, es ist in einem Paket mit dem Namen bsdmainutilsDebian enthalten:

column -t foo

Ausgabe:

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

Auszug aus column(1)meinem System:

...

-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
quelle
groß! Danke vielmals! Es war bereits auf meinem Computer installiert.
Sebastian
11
Möglicherweise möchten Sie die -s $'\t'(jedoch nicht in jeder Spaltenimplementierung gefundene) hinzufügen, falls einige der Felder Leerzeichen enthalten.
Stéphane Chazelas
2
@ RakholiyaJenish $'\t'bedeutet Tabulatorzeichen. Neue Zeile ist $'\n'und so weiter.
Manwe
2
Ich habe das als column -ts: /etc/passwd. Sieht gut aus!
kyb
1
@kyb: sieht noch besser aus mit -n, dh vermeiden Sie das Zusammenführen mehrerer benachbarter Trennzeichen
Thor
10

Mehrere Möglichkeiten:

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 ist kein Standardbefehl, einige Implementierungen / Versionen unterstützen die Option -s nicht. Die Breite der Spalte wird anhand der Eingabe berechnet. Dies bedeutet jedoch, dass die Anzeige erst gestartet werden kann, wenn alle Eingaben eingegeben wurden. $'...'Die Syntax von ksh93 ist auch in zsh und bash enthalten.

Mit zsh:

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

Sie können auch rsals Alternative verwenden column -t:

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

-cÄndert das Trennzeichen für Eingabespalten, setzt jedoch -callein das Trennzeichen für Eingabespalten auf eine Registerkarte. -zStellt die Breite jeder Spalte auf die Breite des längsten Eintrags der Spalte ein, anstatt alle Spalten gleich breit zu machen. Wenn einige Zeilen weniger Spalten als die erste Zeile enthalten, fügen Sie hinzu -n.

Nisetama
quelle
Welches rsist das? Ich habe diesen Befehl weder auf meinem CentOS noch auf meinen Ubuntu / Mint-Systemen installiert.
Anthon
1
@Anthon Dies ist ein BSD-Befehl, der auch mit OS X geliefert wird und nach der Umformungsfunktion in APL benannt ist. Der Name des Debian-Pakets ist einfach rs, damit Sie es mit installieren können apt-get install rs.
Nisetama
Können Sie ein Beispiel dafür geben, wie man den Befehl aufruft (x=$(cat);rs -c -z $(wc -l<<<"$x")<<<"$x")? Ich weiß nicht, wie ich das mit einer CSV-Datei machen würde
baxx
3

Ein weiteres Tool, mit dem dies möglich ist, ist TSV Utilitiestsv-pretty von eBay (Haftungsausschluss: Ich bin der Autor). Der zusätzliche Schritt besteht darin, numerische Felder am Dezimalpunkt auszurichten. Zum Beispiel:

$ 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

Es gibt verschiedene Formatierungsoptionen. Zum Beispiel -uunterstreicht die Kopf- und -fformatiert den Schwimmer in einem Feld in ähnlicher Weise für die Lesbarkeit:

$ 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

Weitere Informationen finden Sie in der tsv-pretty Referenz .

JonDeg
quelle
Das ist wirklich hilfreich
Arefe
1

Die Frage betraf die Ausgabe tabulatorgetrennter Spalten.

Die richtige Antwort ist also eine kleine Anpassung der Antwort von @nisetama. Ich habe die Option -C $ '\ t' hinzugefügt, mit der die Ausgabeformatierung festgelegt wird.

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

Kudo zu @nisetama obwohl :)

thehpi
quelle
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:]]*$,,'
}

PROBENLÄUFE

$ 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 unter: https://github.com/gdbtek/linux-cookbooks/blob/master/libraries/util.bash

Nam Nguyen
quelle
interessante bash-only-lösung - danke fürs teilen
Sebastian
Das ist zu verworren. Und es ist nicht nur Bash, da es externe Befehle gibt, die gerne sedverwendet werden.
Codeforester