Как обработать текстовый файл с несколькими столбцами, чтобы получить другой текстовый файл с несколькими столбцами?

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

Как я могу обработать это и получить файл с 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

Или файл из трех столбцов, например:

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: Да, это безопаснее в использовании "%s", .... Обновлено
Thor
Спасибо за подтверждение. :) То же самое относится и к awkкоманде в вашем другом ответе на этот вопрос, кстати.
Wildcard
20

Поместите каждое поле в строку и постколонку.

Каждое поле в одной строке

тр

tr -s ' ' '\n' < infile

Grep

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

СЭД

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

и т.п.

СЭД

Для 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

колонки (из пакета автогена)

... | 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по умолчанию
Thor
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
Sundeep
источник
9

Как заметил Уилкард, это будет работать только в том случае, если ваш файл хорошо отформатирован, поскольку в нем нет специальных символов, которые оболочка будет интерпретировать как глобусы, и вы будете довольны правилами разделения слов по умолчанию. Если есть какие-либо вопросы о том, пройдут ли ваши файлы этот тест, не используйте этот подход.

Одна из возможностей будет использовать, printfчтобы сделать это как

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

Это будет разбивать слова на содержимое your_file, соединять их и печатать с вкладками между ними. Вы можете использовать больше %sстрок формата, printfчтобы иметь дополнительные столбцы.

Эрик Ренуф
источник
1
Зависит от файла, не содержащего специальных символов. Если он имеет, например, звездочки (*), вы получите очень неожиданные результаты.
Уайлдкарт
4
perl -n0E 'say s/\s+/ ++$n % 4 ?"\t":"\n"/gre' file

(заменить 4 на количество столбцов)

JJoao
источник
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означает «вычислять строки автоматически из столбцов».

Kaz
источник
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
Сергей Колодяжный
источник