Jak przetworzyć plik tekstowy z wieloma kolumnami, aby uzyskać inny plik tekstowy z wieloma kolumnami?

17

Mam plik tekstowy:

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

Jak mogę go przetworzyć i uzyskać 2-kolumnowy plik, taki jak ten:

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

Lub plik z trzema kolumnami, taki jak ten:

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

Wolę dostać rozwiązanie awk, ale inne rozwiązania są mile widziane.

Tylko uczeń
źródło

Odpowiedzi:

1

Możesz to również zrobić za pomocą pojedynczego wywołania 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"
}

Uruchom tak:

awk -f reshape.awk n=2 infile

Lub jako jedna linijka:

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

Wynik:

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

Lub z 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
Thor
źródło
Nie ma to zastosowanie $1jako formatu ciąg do printf?
Wildcard,
@Wildcard: Racja, korzystanie z niej jest bezpieczniejsze "%s", .... Zaktualizowano
Thor
Dziękuję za potwierdzenie. :) Nawiasem awkmówiąc, to samo dotyczy polecenia w drugiej odpowiedzi na to pytanie.
Wildcard,
20

Umieść każde pole w wierszu i postkolumnowe.

Każde pole w jednej linii

tr

tr -s ' ' '\n' < infile

grep

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

sed

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

lub bardziej przenośny:

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

awk

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

lub

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

Kolumnowy

pasta

Dla 2 kolumn:

... | paste - -

Dla 3 kolumn:

... | paste - - -

itp.

sed

Dla 2 kolumn:

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

Dla 3 kolumn:

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

itp.

xargs

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

Jako xargszastosowania /bin/echodo drukowania, pamiętaj, że dane, które wygląda jak opcji echobędą interpretowane jako takie.

awk

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

pr

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

lub

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

kolumny (z pakietu autogenicznego)

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

Typowa wydajność:

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
Thor
źródło
2
Zatrzask. +1 pan
Steven Penny
Czy xargslinia nie powinna dzwonić echoczy printf?
Wildcard,
1
@Wildcard: xargspołączenia /bin/echodomyślnie
Thor
1
Wow, nie miałem pojęcia! Jest nawet określony przez POSIX . Dzięki!
Wildcard,
@Wildcard: Wysyłanie danych, xargsktóre wygląda jak opcje /bin/echopowodujące problemy ... Dodałem ostrzeżenie.
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
Sundeep
źródło
9

Jak wskazał Wildcard, będzie to działać tylko wtedy, gdy plik jest ładnie sformatowany, ponieważ nie ma żadnych znaków specjalnych, które powłoka będzie interpretować jako globs i jesteś zadowolony z domyślnych reguł podziału słów. Jeśli pojawi się pytanie, czy Twoje pliki „przejdą” ten test, nie używaj tego podejścia.

Jedną z możliwości byłoby użycie go printfdo zrobienia tego

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

Spowoduje to podział wyrazów na treść your_filei sparuje je i wydrukuje z zakładkami pomiędzy nimi. Możesz użyć więcej %sciągów formatu w, printfaby mieć dodatkowe kolumny.

Eric Renouf
źródło
1
Zależy od pliku nie zawierającego znaków specjalnych. Jeśli na przykład ma jakieś gwiazdki (*), otrzymasz bardzo nieoczekiwane wyniki.
Wildcard,
4
perl -n0E 'say s/\s+/ ++$n % 4 ?"\t":"\n"/gre' file

(zamień 4 na liczbę kolumn)

JJoao
źródło
4

rsNarzędzie BSD (zmiana kształtu):

$ 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 2to wiersze i kolumny . Określenie 0oznacza „oblicz wiersze automatycznie na podstawie kolumn”.

Kaz
źródło
3

Podejście skryptowe w języku Python.

Podstawową ideą jest spłaszczenie wszystkich słów w tekście na jedną listę, a następnie wydrukowanie nowego wiersza po każdym drugim elemencie (to jest do kolumnowania w dwóch kolumnach). Jeśli chcesz 3 kolumny, zmień index%2naindex%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 = []

Przykładowe dane wyjściowe:

$ 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

Wersja trzykolumnowa (jak wspomniano powyżej, tylko index%3 == 0zmieniona)

$ 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
Sergiy Kolodyazhnyy
źródło