Esiste un semplice comando per l'output di colonne delimitate da tabulazioni?


67

Ad esempio, ho un file (prodotto con echo -e "var1\tvar2\t\var3\tvar4" > foo) che viene emesso come:

$ 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

Preferirei l'output in questo modo (qui ho usato vime :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

Posso ottenere la stessa funzionalità con catse uso $ tabs=15in bash (vedi questa domanda ). Esiste un programma che esegue automaticamente questo tipo di formattazione? Non voglio sperimentare il tabsvalore prima di catcreare un file.

Risposte:


87

Di solito uso il columnprogramma per questo, è in un pacchetto chiamato bsdmainutilssu Debian:

column -t foo

Produzione:

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

Estratto dal column(1)mio sistema:

...

-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.

...

grande! molte grazie! Era già installato sul mio computer.
Sebastian,

11
potresti voler aggiungere -s $'\t'(non presente in tutte le implementazioni di colonne) nel caso in cui alcuni dei campi contengano spazi.
Stéphane Chazelas,

2
@RakholiyaJenish $'\t'significa carattere tab. La nuova linea è $'\n'e così via.
Manwe,

2
L'ho usato come column -ts: /etc/passwd. Sembra fico!
Kyb

1
@kyb: sembra persino migliore -n, cioè evita di unire più delimitatori adiacenti
Thor

10

Diverse opzioni:

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'

La colonna è un comando non standard, alcune implementazioni / versioni non supportano l'opzione -s. Calcola la larghezza della colonna in base all'input, ma ciò significa che può iniziare a visualizzare solo una volta che tutto l'input è stato inserito. $'...'è la sintassi ksh93 che si trova anche in zsh e bash.

Con zsh:

values=(
  case elems messing nlsys
  "$var1" "$var2" "$var3" "$var4"
)
print -arC4 -- "$values[@]"

4

Puoi anche usare rsin alternativa a column -t:

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

-ccambia il separatore della colonna di input, ma -cda solo imposta il separatore della colonna di input su una scheda. -zimposta la larghezza di ciascuna colonna sulla larghezza della voce più lunga della colonna anziché rendere tutte le colonne della stessa larghezza. Se alcune righe hanno meno colonne della prima riga, aggiungi -n.


Che rscos'è? Non ho installato quel comando sul mio CentOS né sui miei sistemi Ubuntu / Mint.
Anthon,

1
@Anthon È un comando BSD fornito anche con OS X, che prende il nome dalla funzione di risagoma in APL. Il nome del pacchetto Debian è giusto rs, quindi puoi installarlo con apt-get install rs.
nisetama,

potresti fornire un esempio di come si chiamerebbe il comando (x=$(cat);rs -c -z $(wc -l<<<"$x")<<<"$x")? Non so come farei per usarlo con un file CSV
baxx

3

Un altro strumento che può farlo è tsv-prettydalle Utilità TSV di eBay (dichiarazione di non responsabilità: sono l'autore). Prende il passaggio aggiuntivo di allineare i campi numerici sul punto decimale. Per esempio:

$ 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

Esistono diverse opzioni di formattazione. Ad esempio, -usottolinea l'intestazione e -fformatta i float in un campo in modo simile per la leggibilità:

$ 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

Maggiori informazioni sono disponibili nel riferimento tsv-pretty .


Questo è davvero utile
Arefe,

1

La domanda riguardava l'output di colonne delimitate da tabulazioni.

Quindi la risposta corretta è un piccolo adattamento della risposta di @nisetama. Ho aggiunto l'opzione -C $ '\ t' che imposta la formattazione dell'output.

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

Kudo è su @nisetama però :)


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

CAMPIONI DI CAMPIONE

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

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


interessante soluzione solo bash - grazie per la condivisione
Sebastian

Questo è troppo contorto. E non è solo bash poiché ci sono comandi esterni come sedl'uso.
codeforester
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.