- Вопрос или проблема
- Каждое поле на отдельной строке
- tr
- grep
- sed
- awk
- Колонируйте
- paste
- sed
- xargs
- awk
- pr
- columns (из пакета autogen)
- Типичный вывод:
- Подход с использованием Python скрипта.
- Ответ или решение
- 1. Постановка задачи
- 2. Разделение каждого элемента на новую строку
- Использование tr:
- Использование grep:
- Использование sed:
- 3. Организация данных в столбцы
- Сортировка в 2 столбца с использованием paste:
- Сортировка в 3 столбца:
- 4. Инструмент awk для обработки файла
- Заключение
Вопрос или проблема
У меня есть текстовый файл:
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, но другие решения также приветствуются.
Разместите каждое поле на отдельной строке и пост-колонируйте.
Каждое поле на отдельной строке
tr
tr -s ' ' '\n' < infile
grep
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
Колонируйте
paste
Для 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
... | pr -at -number-of-desired-columns
или
... | pr -at -s$'\t' -number-of-desired-columns
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
$ 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
Как отметил Wildcard, это будет работать только в том случае, если ваш файл хорошо отформатирован, то есть в нем нет специальных символов, которые оболочка интерпретирует как шаблоны, и вы довольны стандартными правилами разбиения на слова. Если есть сомнения по поводу того, пройдут ли ваши файлы этот тест, не используйте этот метод.
Одной из возможностей было бы использовать printf
, чтобы сделать это, например
printf '%s\t%s\n' $(cat your_file)
Это будет разбивать содержимое your_file
на слова, объединять их и выводить с табуляцией между ними. Вы можете использовать больше форматов %s
в printf
, чтобы получить дополнительные колонки.
perl -n0E 'say s/\s+/ ++$n % 4 ?"\t":"\n"/gre' file
(замените 4 на количество нужных колонок)
Утилита BSD rs
(reshape):
$ 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
означает “автоматически рассчитать количество строк из количества колонок”.
Подход с использованием 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
Вы можете также сделать это с помощью одного вызова GNU awk:
reshape.awk
# Установите awk для разделения входных данных по пробельным символам и
# используйте табуляцию как разделитель полей вывода
BEGIN {
RS="[ \t\n]+"
OFS="\t"
}
# Вывод с использованием OFS или ORS в зависимости от индекса элемента
{
printf "%s", $1 (NR%n == 0 ? ORS : OFS)
}
# Добавить недостающий перевод строки, когда последняя строка не заполнена
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
Два столбца
perl -pne "s/ /\n/g" filename| sed '/^$/d'| sed "N;s/\n/ /g"
Вывод
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
Три столбца
perl -pne "s/ /\n/g" filename| sed '/^$/d'| sed "1~3N;s/\n/ /g"| sed "N;s/\n/ /g"
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
Использование Raku (ранее известного как Perl_6)
Преобразование в 2-колоночный вывод:
~$ raku -e '.put for words.batch(2);' file
Преобразование в 3-колоночный вывод:
~$ raku -e '.put for words.batch(3);' file
Raku имеет функцию words
, которая разбивает по пробелам. После разделения, элементы могут быть снова batch
ены вместе. Вы используете batch
в Raku, если ожидаете неполный/частичный набор элементов в конце (эквивалент rotor(partial => True)
). Если у вас есть необходимость отбросить финальный неполный/частичный набор элементов в конце, используйте rotor()
с умолчаниями.
Пример входных данных:
a aa aaa b bb bbb c cc ccc
d dd ddd e ee eee f ff fff
g gg гgg h hh hhh i ii iii
j jj jjj
Пример вывода (2-колонный, объединенный на \t
):
~$ raku -e '.join("\t").put for words.batch(2);' file
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
Пример вывода (3-колонный, объединенный на \t
):
~$ raku -e '.join("\t").put for words.batch(3);' file
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
Наконец, если ваши начальные элементы не разделены пробелами, вы можете slurp
файл сразу и, например, .split(/ \, | \n /)
разбить по запятым и переводам строк. Смотрите первую ссылку ниже для примера.
https://unix.stackexchange.com/a/686651/227738
https://raku.org
Ответ или решение
Конечно, обработка текстовых файлов для преобразования из одного формата в другой — это важный аспект работы с данными в ИТ, который требует как точности, так и эффективного использования инструментов. В данном случае задача заключается в том, чтобы преобразовать файл с х столбцами в файл с y столбцами. Давайте рассмотрим возможные подходы и инструменты для выполнения этой задачи, уделяя особое внимание инструменту awk
, который упоминается как предпочтительный.
1. Постановка задачи
У вас имеется текстовый файл с неравномерным количеством значений в каждой строке, и вам необходимо преобразовать его так, чтобы на выходе получился файл с фиксированным количеством столбцов, например, 2 или 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
2. Разделение каждого элемента на новую строку
Для подготовки к дальнейшему разделению элементов на столбцы, сначала необходимо преобразить данные так, чтобы каждый элемент находился на своей отдельной строке. Это можно сделать с помощью нескольких инструментов:
Использование tr
:
tr -s ' ' '\n' < infile
Использование grep
:
grep -o '[[:alnum:]]*' infile
Использование sed
:
sed 's/\s\+/\n/g' infile
3. Организация данных в столбцы
Сортировка в 2 столбца с использованием paste
:
После того, как у нас есть данные с одним элементом на строку, мы можем использовать инструмент paste
для организации данных, например, в два столбца:
sed 's/\s\+/\n/g' infile | paste - -
Сортировка в 3 столбца:
Аналогично, для трёх столбцов:
sed 's/\s\+/\n/g' infile | paste - - -
4. Инструмент awk
для обработки файла
Одним из самых мощных инструментов для обработки текстовых файлов является awk
. Он позволяет гибко настраивать процесс пост-обработки данных и применять сложные правила:
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
Здесь n
— это количество столбцов, которые вы хотите получить на выходе.
Заключение
Точная и эффективная обработка текстовых файлов требует правильного выбора инструментов и алгоритмов. В качестве дополнения к awk
, вы можете использовать другие команды Unix, такие как sed
, tr
и paste
, которые оптимизируют автоматизацию процесса. Объединение таких инструментов позволяет ИТ-специалистам успешно решать задачи по преобразованию данных даже в сложных ситуациях.
Важно помнить, что каждый способ имеет свои особенности, и выбор подходящего метода зависит от конкретных требований вашего проекта и структуры данных.