Як обробити текстовий файл з декількома стовпцями, щоб отримати ще один текстовий файл з декількома стовпцями?


17

У мене є текстовий файл:

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

Як я можу це обробити і отримати файл із двома стовпцями, як це:

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

Або файл із трьох стовпців, як це:

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

Я вважаю за краще отримати awk рішення, але інші рішення також вітаються.

Відповіді:


1

Ви також можете це зробити одним викликом 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"
}

Виконайте це так:

awk -f reshape.awk n=2 infile

Або як однолінійний:

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

Вихід:

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

Або з 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

Чи не використовується це $1як рядок формату для printf?
Wildcard

@Wildcard: Правильно, безпечніше використовувати "%s", .... Оновлено
Тор

Дякуємо за підтвердження. :) Те ж саме стосується awkкоманди в іншій вашій відповіді на це питання, до речі.
Wildcard

20

Поставте кожне поле на рядок і поставите стовпчик.

Кожне поле по одному рядку

тр

tr -s ' ' '\n' < infile

греп

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

sed

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

або більш портативний:

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

awk

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

або

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

Columnate

пасти

Для 2 стовпців:

... | paste - -

Для 3 стовпців:

... | paste - - -

тощо.

sed

Для 2 стовпців:

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

Для 3 стовпців:

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

тощо.

xargs

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

Як xargsвикористовує /bin/echoдля друку, потрібно враховувати , що дані , які скидаються варіанти echoбудуть інтерпретуватися як такі.

awk

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

пр

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

або

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

стовпці (з пакета autogen)

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

Типовий вихід:

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
Слэм занурився. +1 сер
Стівен Пенні

Не повинен xargsдзвінок на лінію echoабо printf?
Wildcard

1
@Wildcard: за замовчуванням xargsдзвінки/bin/echo
Тор

1
Нічого собі, я поняття не мав! Це навіть визначено POSIX . Спасибі!
Wildcard

@Wildcard: Надсилання даних xargs, схоже на варіанти, /bin/echoвикликає проблеми ... Я додав попередження.
Тор

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

Як зауважив Уайлдкард, це буде працювати лише в тому випадку, якщо ваш файл буде добре відформатований, оскільки немає спеціальних символів, які оболонка буде інтерпретувати як глобуси, і ви задоволені правилами розбиття слів за замовчуванням. Якщо є питання щодо того, чи будуть ваші файли "пройти" цей тест, не використовуйте цей підхід.

Однією з можливостей було б скористатися, printfщоб зробити це так

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

Це зробить розділення слів на вміст your_fileі з’єднає їх та надрукує їх між вкладками. Ви можете використовувати більше %sформатних рядків у, printfщоб мати додаткові стовпці.


1
Залежить від файлу, який не містить спеціальних символів. Якщо у вас, наприклад, є будь-які зірочки (*), ви отримаєте дуже несподівані результати.
Wildcard

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

(замініть 4 на кількість стовпців)


4

rsУтиліта BSD (переформатування):

$ 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це рядки та стовпці . Вказівка 0означає "автоматично обчислювати рядки з стовпців".


3

Підхід сценарію Python.

Основна ідея тут - згладити всі слова у вашому тексті в одному списку, а потім надрукувати новий рядок після кожного другого елемента (це для того, щоб зібрати в два стовпці). Якщо ви хочете 3 стовпчики, перейдіть index%2наindex%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 = []

Вибірка зразка:

$ 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

Триколонна версія (як сказано вище, лише index%3 == 0змінена)

$ 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.