Come elaborare un file di testo multi colonna per ottenere un altro file di testo multi colonna?


17

Ho un file di testo:

a   aa  aaa     b   bb  bbb     c   cc  ccc
d   dd  ddd     e   ee  eee     f   ff  fff
g   gg  ggg     h   hh  hhh     i   ii  iii
j   jj  jjj

Come posso elaborarlo e ottenere un file a 2 colonne come questo:

a   aa
aaa b
bb  bbb
c   cc
ccc d
dd  ddd
e   ee
eee f
ff  fff
g   gg
ggg h
hh  hhh
i   ii
iii j
jj  jjj

O un file a tre colonne come questo:

a   aa  aaa
b   bb  bbb
c   cc  ccc
d   dd  ddd
e   ee  eee
f   ff  fff
g   gg  ggg
h   hh  hhh
i   ii  iii
j   jj  jj

Preferisco ottenere una soluzione eccezionale ma anche altre soluzioni sono benvenute.

Risposte:


1

Puoi anche farlo con una singola invocazione di GNU awk:

reshape.awk

# Set awk to split input at whitespace characters and
# use tab as the output field separator 
BEGIN {
  RS="[ \t\n]+"
  OFS="\t"
}

# Print using OFS or ORS based on the element index
{
  printf "%s", $1 (NR%n == 0 ? ORS : OFS)
}

# Append a missing new-line when last row is not full
END { 
  if( NR%n != 0) 
    printf "\n"
}

Eseguilo in questo modo:

awk -f reshape.awk n=2 infile

O come one-liner:

awk -v n=2 'BEGIN { RS="[ \t\n]+"; OFS="\t" } { printf "%s", $1 (NR%n == 0 ? ORS : OFS) } END { if( NR%n != 0) printf "\n" }' infile

Produzione:

a   aa
aaa b
bb  bbb
c   cc
ccc d
dd  ddd
e   ee
eee f
ff  fff
g   gg
ggg h
hh  hhh
i   ii
iii j
jj  jjj

O con n=3:

a   aa  aaa
b   bb  bbb
c   cc  ccc
d   dd  ddd
e   ee  eee
f   ff  fff
g   gg  ggg
h   hh  hhh
i   ii  iii
j   jj  jjj

Questo non usa $1come stringa di formato per printf?
Carattere jolly

@Wildcard: giusto, è più sicuro da usare "%s", .... Aggiornato
Thor,

Grazie per la conferma. :) Lo stesso vale per il awkcomando nell'altra risposta a questa domanda, tra l'altro.
Carattere jolly

20

Metti ogni campo su una riga e post-colonna.

Ogni campo su una riga

TR

tr -s ' ' '\n' < infile

grep

grep -o '[[:alnum:]]*' infile

sed

sed 's/\s\+/\n/g' infile

o più portatile:

sed 's/\s\+/\
/g' infile

awk

awk '$1=$1' OFS='\n' infile

o

awk -v OFS='\n' '$1=$1' infile

colonnato

incolla

Per 2 colonne:

... | paste - -

Per 3 colonne:

... | paste - - -

eccetera.

sed

Per 2 colonne:

... | sed 'N; s/\n/\t/g'

Per 3 colonne:

... | sed 'N; N; s/\n/\t/g'

eccetera.

xargs

... | xargs -n number-of-desired-columns

Come xargsusi /bin/echoper la stampa, attenzione che i dati che sembrano opzioni echoverranno interpretati come tali.

awk

... | awk '{ printf "%s", $0 (NR%n==0?ORS:OFS) }' n=number-of-desired-columns OFS='\t'

pr

... | pr -at -number-of-desired-columns

o

... | pr -at -s$'\t' -number-of-desired-columns

colonne (dal pacchetto autogen)

... | columns -c number-of-desired-columns

Uscita tipica:

a   aa  aaa
b   bb  bbb
c   cc  ccc
d   dd  ddd
e   ee  eee
f   ff  fff
g   gg  ggg
h   hh  hhh
i   ii  iii
j   jj  jjj

2
Schiacciata. +1 signore
Steven Penny,

La xargslinea non dovrebbe chiamare echoo printf?
Carattere jolly

1
@Wildcard: xargschiamate /bin/echodi default
Thor

1
Wow, non ne avevo idea! È anche specificato da POSIX . Grazie!
Carattere jolly

@Wildcard: l'invio di dati xargsche sembrano opzioni per /bin/echocausare problemi ... Ho aggiunto un avviso.
Thor,

9
$ sed -E 's/\s+/\n/g' ip.txt | paste - -
a   aa
aaa b
bb  bbb
c   cc
ccc d
dd  ddd
e   ee
eee f
ff  fff
g   gg
ggg h
hh  hhh
i   ii
iii j
jj  jjj

$ sed -E 's/\s+/\n/g' ip.txt | paste - - -
a   aa  aaa
b   bb  bbb
c   cc  ccc
d   dd  ddd
e   ee  eee
f   ff  fff
g   gg  ggg
h   hh  hhh
i   ii  iii
j   jj  jjj

9

Come sottolineato da Wildcard, questo funzionerà solo se il tuo file è ben formattato, in quanto non ci sono caratteri speciali che la shell interpreterà come globs e sei soddisfatto delle regole predefinite di suddivisione delle parole. Se hai qualche domanda sul fatto che i tuoi file "superino" quel test, non utilizzare questo approccio.

Una possibilità sarebbe quella di usare printfper farlo come piace

printf '%s\t%s\n' $(cat your_file)

Ciò comporterà una suddivisione delle parole sul contenuto di your_filee li abbinerà e li stamperà con le schede in mezzo. È possibile utilizzare più %sstringhe di formato in printfper avere colonne aggiuntive.


1
Dipende dal file che non contiene caratteri speciali. Se ha, ad esempio, degli asterischi (*) otterrai risultati inaspettati.
Carattere jolly

4
perl -n0E 'say s/\s+/ ++$n % 4 ?"\t":"\n"/gre' file

(sostituisci 4 con il numero di colonne)


4

rsUtilità BSD (rimodella):

$ rs 0 2
a   aa  aaa     b   bb  bbb     c   cc  ccc
d   dd  ddd     e   ee  eee     f   ff  fff
g   gg  ggg     h   hh  hhh     i   ii  iii
j   jj  jjj
[Ctrl-D][Enter]
a    aa
aaa  b
bb   bbb
c    cc
ccc  d
dd   ddd
e    ee
eee  f
ff   fff
g    gg
ggg  h
hh   hhh
i    ii
iii  j
jj   jjj

0 2è righe e colonne . Specificare 0significa "calcolare automaticamente le righe dalle colonne".


3

Approccio allo script Python.

L'idea di base qui è appiattire tutte le parole del testo in un elenco e quindi stampare una nuova riga dopo ogni secondo elemento (che è per la colonna in due colonne). Se vuoi 3 colonne, cambia index%2inindex%3

#!/usr/bin/env python3
import sys

items = [i for l in sys.stdin 
           for i in l.strip().split()]
line = []
for index,item in enumerate(items,1):
    line.append(item)
    if index%2 == 0:
       print("\t".join(line))
       line = []

Uscita campione:

$ python recolumnate.py < input.txt                                            
a   aa
aaa b
bb  bbb
c   cc
ccc d
dd  ddd
e   ee
eee f
ff  fff
g   gg
ggg h
hh  hhh
i   ii
iii j
jj  jjj

Versione a tre colonne (come detto sopra, solo index%3 == 0modificata)

$ cat recolumnate.py                                                           
#!/usr/bin/env python3
import sys

items = [i for l in sys.stdin 
           for i in l.strip().split()]
line = []
for index,item in enumerate(items,1):
    line.append(item)
    if index%3 == 0:
       print("\t".join(line))
       line = []

$ python recolumnate.py < input.txt                                            
a   aa  aaa
b   bb  bbb
c   cc  ccc
d   dd  ddd
e   ee  eee
f   ff  fff
g   gg  ggg
h   hh  hhh
i   ii  iii
j   jj  jjj
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.