Для решения с использованием awk
, см. answer by kev.
Для улучшенного решения с использованием grep -f
, рассмотреть вопрос об использовании bash
process substitution:
grep -f <(sed 's/.*/^&,/' file2.txt) file1.csv
Это использует sed
на линиях в file2.txt
поставить каретку в начале каждой строки и запятой в конце, так что при обработке в качестве регулярного выражения (GNU?) grep
шаблоны соответствуют только точной величине поля в начале строки. Если у вас нет bash
, вы можете быть в состоянии использовать:
sed 's/.*/^&,/' file2.txt | grep -f - file1.csv
Однако не все версии grep
читает стандартный ввод при указании -f -
(версия на Mac OS X не, например, но GNU grep
делает).
В качестве альтернативы, вы можете использовать команду join
с соответствующими видами:
join -o 1.1,1.2,1.3,1.4 -t, <(sort file1.csv) <(sort file2.txt)
Если вы уверены, что файлы уже отсортированы, можно упростить, что просто:
join -o 1.1,1.2,1.3,1.4 -t, file1.csv file2.txt
В Perl, вы можете использовать:
#!/usr/bin/env perl
use strict;
use warnings;
my $file = 0;
my %rows;
while (<>)
{
chomp;
$rows{$_}++ if ($file == 0);
if ($file == 1)
{
my($id) = split /,/;
print "$_\n" if defined $rows{$id};
}
}
continue
{
$file = 1 if eof;
}
Возможно, есть другие способы сделать это тоже; например, вы можете найти применение для таких модулей, как Text::CSV.
Однако этот код читает каждую строку. Если он из первого файла, он создает запись $rows{$_}++
, чтобы записать, что номер был замечен. Порядок и повторение не имеют значения. Во втором (и последующих) файлах он разбивает первое поле с запятой из строки и проверяет, было ли это число найдено в первом файле; если это так, он печатает всю строку. Блок continue
обнаруживает, когда код достигает EOF в первом файле (в частности) и устанавливает $file = 1;
, когда он это делает. Он изоморфен решению awk
. Это немного подробный. Существует режим -a
(awk
), но из-за того, что два файла нужно обрабатывать по-разному, это довольно сложно, чтобы заставить его работать правильно.
Из этого, я думаю, решение grep -f
, вероятно, является самым простым, поскольку file2.txt
не слишком большой (и я не уверен, какой предел был бы - но, вероятно, удивительно большой).
Для инструмента обработки файлов CSV общего назначения рассмотрите csvfix.
Ok. Я смог решить это с помощью простой команды grep. grep -f file2.txt file1.csv. Мне просто интересно узнать, есть ли другие способы. – Teja
Ваше приятное простое решение также подберет строки '10, p, q, r' и' 300, x, y, z' из 'file1.csv' (не говоря уже о' 444,1,2,33') ; это нормально? Если нет, вам нужно использовать команду «join» с соответствующими типами, вероятно (или 'awk' и ассоциативными массивами, или Perl, или Python, или, может быть,' grep -f <(sed 's /.*/^& ,/'file2.txt) file1.csv'). –
Вы также можете просмотреть [csvfix] (http://code.google.com/p/csvfix) для инструмента для управления файлами CSV. –