У меня есть большой CSV-файл (Test.csv), который выглядит так:
1,2,3,A,5
1,2,3,B,5
1,2,3,E,5
1,2,3,D,5
1,2,3,Z,5
1,2,3,B,5
Я хочу напечатать строки, в которых 4-й столбец имеет одинаковое содержимое в разных файлах. На самом деле, мне нужно объединить эти строки, которые имеют одинаковое содержимое, в новый файл csv или txt, названный как содержимое 4-го столбца. Например:
Выход:
Файл А
1,2,3,A,5
1,2,3,A,5
1,2,3,A,5
Файл Б
1,2,3,B,5
1,2,3,B,5
Поскольку входной файл большой, я понятия не имею, сколько различных шаблонов в этом 4-м столбце. Столбец 4 содержит только слова, а другие столбцы содержат слова и/или числа.
Поскольку у меня нет опыта, я исследовал похожие вопросы и даже попробовал следующий код:
awk 'NR==FNR{a[$4]=NR; next} $NF in a {print > "outfile" a[$NF]}' Test.csv
но ничего не получилось. Может кто-нибудь помочь, пожалуйста? Заранее спасибо.
решение1
Это будет эффективно работать при использовании сортировки POSIX и любого awk в любой оболочке на любой машине UNIX:
$ sort -t, -k4,4 test.csv |
awk -F, '$4!=prev{close(out); out="File"$4; prev=$4} {print > out}'
$ head -n 20 File*
==> FileA <==
1,2,3,A,5
==> FileB <==
1,2,3,B,5
1,2,3,B,5
==> FileD <==
1,2,3,D,5
==> FileE <==
1,2,3,E,5
==> FileZ <==
1,2,3,Z,5
Некоторые моменты, на которые следует обратить внимание:
- некоторым awk необходимо заключать в скобки выражение с правой стороны перенаправления вывода, и
- некоторые awk терпят неудачу, если вы не закрываете выходные файлы по мере их поступления, и таким образом пытаются сохранить слишком много открытых файлов, когда их число превышает дюжину или около того, и
- сохранение нескольких открытых выходных файлов очень неэффективно во всех awk, которые это позволяют, и
- Построчное закрытие выходных файлов для учета этого фактора будет крайне неэффективным во всех awks.
решение2
Вы должны иметь возможность просто использовать поле в имени выходного файла. Простое решение:
awk -F, '{print > ("file_" $4 ".csv")}' Test.csv
Это работает, по крайней мере, в GNU awk и создает file_A.csvи file_B.csvт. д. Обратите внимание, что при этом все выходные файлы остаются открытыми, и чем больше их, тем медленнее процесс, особенно если вы достигнете лимита открытых файлов на процесс.
-F,устанавливает разделитель полей на запятую.
Я не уверен, что должен делать показанный вами сценарий.
решение3
Что-то вроде этого:
$ awk -F, '{ print $0 >> "file-" $4 ".txt"; }' ./tmp.txt
Как упоминает ответ @ilkkachu, флаг -F— это изменение разделителя полей с пробелов по умолчанию на запятую. Вы должны использовать
>>вместо >
, чтобы не перезаписывать файл, если он существует.
решение4
Питон
#!/usr/bin/python
uni=[]
k=open('file.txt','r')
for i in k:
g=i.split(",")[3].strip()
if g not in uni:
uni.append(g)
for m in uni:
f=open("{0}.txt".format(m),'w')
l=open('file.txt','r')
for d in l:
if m in d.split(",")[3].strip():
f.write(d)
Лучшее решение уже предоставлено в awk, это просто моя попытка
for i in `awk -F "," '{if(!seen[$4]++)print $4}' file.txt`; do awk -v i="$i" -F "," '$4==i{print $0}' file.txt >$i.txt; done


