Вот версия, ориентированная на bash; выглядит очень похоже на версию awk oliv
unset fileheads fields
declare -A fileheads
declare -A fields
for f in *.csv
do
IFS=, fileheads[$f]=$(head -n1 "$f");
set -f
for field in ${fileheads[$f]}
do
fields[$field]+=x
done
set +f
done
for field in ${!fields[*]}
do
[[ ${#fields[$field]} -gt 1 ]] || continue
for file in ${!fileheads[*]}
do
[[ ${fileheads[$file]} =~ $field ]] && echo "$file has $field"
done
echo
done
. При этом поля (строка 1) каждого файла собираются в ассоциативный массив fileheads
, индексированный по имени файла. Он также собирает список того, сколько раз он видел каждое имя поля. Здесь мы предполагаем, что запятые не появляются в самих названиях полей.
Затем мы перебираем все известные поля; если какой-либо из них был замечен более одного раза, мы просматриваем файлы (индексы в массиве fileheads
), чтобы увидеть, содержит ли какой-либо из них это поле. По крайней мере два файла должны соответствовать этому критерию; их имена файлов и связанное поле выводятся эхом, за ними следует пустая строка для удобства чтения.
Пример выполнения:
$ head -n1 *.csv
==> EVOP_IMAGE.csv <==
"evop_image_id","evop_id","evo_ang_id","evo_collection","file_format","image_name","image_path","image_type"
==> EVO_ANGLE.csv <==
"evo_ang_id","angle_description"
==> IMAGE_TYPE.csv <==
"id","image_type","group","description"
EVOP_IMAGE.csv has "evo_ang_id"
EVO_ANGLE.csv has "evo_ang_id"
EVOP_IMAGE.csv has "image_type"
IMAGE_TYPE.csv has "image_type"
awk решение:
--для вывода только тех записей, которые встречаютсяне менее3 раза:
awk '++a[$3]==3{ print $3 }' file
++a[$3]
-последовательно увеличивающееся количество уникальных значений 3-го поля --для вывода только тех записей, которые встречаютсяровно3 раза:
awk '{++a[$3]}END{ for(i in a) if(a[i]==3) print i }' file
Выход:
APPLE
Пропустите выходные данные вашего конвейера через awk '$1 == 3 { print $2 }'
, чтобы получить только APPLE
.
В качестве альтернативы, считайте с помощью awk
с самого начала:
awk '{ c[$3]++; r[$3] = r[$3] ? r[$3] ORS $0 : $0 } END { for (i in c) { if (c[i] == 3) print r[i] } }' file
1 2 APPLE
8 2 APPLE
3 4 APPLE
Скрипт awk
будет подсчитывать в c
, сколько раз встречаются значения в столбце 3. Каждая входная строка добавляется к r
, который представляет собой ассоциативный массив, подобный c
, с ключом в третьем столбце.
В конце выводятся только те строки, в которых 3-й столбец встречается ровно три раза.
Другой подход состоит в том, чтобы просмотреть файл дважды, сначала для создания ссылки, а затем для фильтрации по мере необходимости.
$ awk 'NR==FNR{a[$3]++; next} a[$3]==3' ip.txt ip.txt
1 2 APPLE
8 2 APPLE
3 4 APPLE
$ awk 'NR==FNR{a[$3]++; next} a[$3]==2' ip.txt ip.txt
3 4 PEAR
9 3 LEMON
9 3 LEMON
8 3 PEAR
$ awk 'NR==FNR{a[$3]++; next} a[$3]<2' ip.txt ip.txt
A B C
8 3 ORANGE
Что ж, возможно, это не самый элегантный способ, но то, что следует ниже, работает. Он расширяет то, что вы уже сделали, анализируя каждую строку, чтобы отфильтровать те, у которых количество вхождений строго не превышает 2 .
awk '{print $3}' yourInputFile | sort | uniq -c | while read -r line
do
echo $line | [ `awk '{print $1}'` -gt 2 ] && echo $line | awk '{print $2}'
done
А если вы захотите ограничить отображение строками, число вхождений которых строго равно 3 , это еще проще. grep
можно использовать как @wvxvw
, предложенный в комментариях. В этом случае вам даже не нужно выполнять итерацию, но вы должны экранировать grep
, чтобы не получать значения, которые начинаются с 3, но больше, например 30:
awk '{print $3}' yourInputFile | sort | uniq -c | grep '^\s*3\s' | awk '{print $2}'
В обоих случаях вывод:
APPLE