2013-12-08 6 views
1

Я хочу обновить file1 на основе file2. Если какая-либо строка является новой в файле2, она должна быть добавлена ​​в файл1. Если какая-либо строка из файла2 уже находится в файле1, обновите эту строку с помощью строки из файла2, если время больше в файле2.awk | Добавить новую строку или обновить существующую строку в файле

file1

DL,1111111100,201312051013,val,FIX01,OptIn,N,Ext1,Ext2 
DL,1111111101,201312051014,val,FIX01,OptIn,Y,Ext1,Ext2 
DL,1111111102,201312051015,val,FIX01,OptIn,Y,Ext1,Ext2 
DL,1111111103,201312051016,val,FIX01,OptIn,N,Ext1,Ext2 

file2

DL,1111111101,201312041013,val,FIX02,OptIn,N,Ext1,Ext2 
DL,1111111102,201312051016,val,FIX02,OptIn,N,Ext1,Ext2 
DL,1111111102,201312051017,val,FIX02,OptIn,N,Ext1,Ext2 
DL,1111111104,201312051014,val,FIX01,OptIn,Y,Ext1,Ext2 
DL,1111111104,201312051016,val,FIX02,OptIn,Y,Ext1,Ext2 

newfile1

DL,1111111100,201312051013,val,FIX01,OptIn,N,Ext1,Ext2 
DL,1111111101,201312051014,val,FIX01,OptIn,Y,Ext1,Ext2 
DL,1111111102,201312051017,val,FIX02,OptIn,N,Ext1,Ext2 
DL,1111111103,201312051016,val,FIX01,OptIn,N,Ext1,Ext2 
DL,1111111104,201312051016,val,FIX02,OptIn,Y,Ext1,Ext2 

Примечания:

  • второе поле Шоул d - уникальный результат.
  • Добавление нового значения: последнее второе поле для значения «1111111104» в file2 взято, которое является более новым (201312051016), тогда старое значение (201312051014) на основе столбца даты (3-е поле).
  • Обновить существующее значение: обновлено «1111111102» с более новым значением на основе даты в третьем столбце
  • file1 очень БОЛЬШОЙ, тогда как файл2 имеет только 5-10 записей.
  • строка с 2-м полем «1111111101» не нуждается в обновлении, потому что ее запись в file1 уже имеет самую последнюю дату «201312051014» по сравнению с новой датой «201312041013» в file2.

Я не пробовал много на это, потому что это действительно имеет сложное условие для меня как новичка ..

BEGIN { FS = OFS = "," } 
FNR == NR { 
    m=$2; 
    a[m] = $0; 
    next 
} 
{ 
    if($2 in a) 
    { 
     split(a[$2],datetime,",") 
     if($3>datetime[3]) 
       print $0; 
     else 
       print a[$2]"Old time" 
    } 
    else print $0"NOMATCH"; 
    delete a[$2]; 
} 
+0

В чем вопрос? Я понятия не имею, чего вы пытаетесь достичь. Попробуйте объяснить, что вы хотите, а не просто размещать некоторые файлы и непонятные записи - тогда кто-то поможет. –

+0

Я извиняюсь за это, если я не могу это объяснить правильно. Теперь я добавил также небольшое резюме. Дайте мне знать, если мне нужно объяснить mote. –

ответ

2

С file1 очень большой, но file2 очень мала (5-10 записей), вам нужно сначала прочитать все file2 в памяти, имея дело с повторяющимися значениями. В результате у вас будет массив, индексированный по номеру записи с новыми данными; вы также должны иметь запись даты для каждой записи в отдельном массиве. Затем, когда вы читаете основной файл, вы просматриваете номер записи и дату в массивах, и если вам нужно, замените сохраненную новую запись на входную старую запись.

Ваш сценарий основной части. Это более сложная, потому что вы не сохранили даты вступления в этом более или менее работает:. Выход

awk -F, ' 
FNR == NR { if (!($2 in date) || date[$2] < $3) { date[$2] = $3; line[$2] = $0; } next; } 
      { if ($2 in date) 
      { 
       if (date[$2] > $3) 
        print line[$2] 
       else 
        print 
       delete line[$2] 
       delete date[$2] 
      } 
      else 
       print 
      } 
END  { for (l in line) print line[l]; }' file2 file1 

Образец для приведенных данных:

DL,1111111100,201312051013,val,FIX01,OptIn,N,Ext1,Ext2 
DL,1111111101,201312051014,val,FIX01,OptIn,Y,Ext1,Ext2 
DL,1111111102,201312051017,val,FIX02,OptIn,N,Ext1,Ext2 
DL,1111111103,201312051016,val,FIX01,OptIn,N,Ext1,Ext2 
DL,1111111104,201312051016,val,FIX02,OptIn,Y,Ext1,Ext2 

Однако, если было 4 новых записей, нет никакой гарантии, что они будут отсортированы по порядку, хотя все они будут в конце списка. Можно было бы обновить сценарий для печати новых записей в соответствующем месте в списке , если вход гарантированно будет в отсортированном порядке. Вам просто нужно выполнить поиск по списку строк, чтобы увидеть, есть ли строки, которые должны быть напечатаны до текущей строки, и если да, сделайте это (и удалите запись, чтобы они не были напечатаны в конце).

Обратите внимание, что уникальность на выходе зависит от уникальности ввода (file1).То есть, если поле 2 на входе повторяется, этот код не будет замечен. Также нет ничего, что можно было бы сделать с нынешним дизайном, даже если бы был замечен дубликат; старая строка была напечатана, поэтому печать новой строки просто вызовет дубликат. Если вы беспокоились об этом, вы могли бы создать сценарий awk, чтобы сохранить все file1 в памяти и печатать только что-либо, когда весь вход был обработан. Излишне говорить, что это использует намного больше памяти, чем текущий дизайн, и, как правило, будет менее эффективным из-за этого. Тем не менее, это может быть сделано, если это необходимо.

+0

Спасибо, Джонатан. Это было быстро и легко .. также не могли бы вы объяснить на втором условии, если? Второе «if» запускается с помощью «{» .. это второй цикл в файле после первого, если условие? –

+0

Есть три блока. Первый - блок «FNR == NR»; он обрабатывает первый обработанный файл aka 'file2' (потому что это когда номер записи файла совпадает с номером общей записи, а потому, что' next' пропускает остальную часть обработки для данной строки). Следующий блок - тот, о котором вы говорите (я думаю); он применяется к каждой строке во втором файле. Он проверяет, известен ли номер записи, и если он есть, а дата замены более поздняя, ​​чем дата в файле ('file1'), тогда он печатает ревизию; в любом случае, он удаляет запись для чистоты. –

+0

Если запись не находится в данных 'file2', запись просто печатается. Третий блок - это блок «END». Он ищет все записи, остающиеся в массиве 'line', и печатает их; они не были сопоставлены ничем в 'file1', поэтому их нужно добавить. –

3

Предполагая, что вы можете начать свой awk следующим образом:

awk -f script.awk input2.csv input1.csv > result.csv 

вы можете использовать следующий скрипт, чтобы получить желаемый результат:

BEGIN { 
    FS = OFS = "," 
} 
FILENAME == "input2.csv" { 
    date[$2] = $3 
    data[$2] = $0 
    used[$2] = 0 
} 
FILENAME == "input1.csv" { 
    if ($2 in date) { 
     used[$2] = 1 
     if ($3 < date[$2]) 
      print data[$2] 
     else 
      print $0 
    } else { 
     print $0 
    } 
} 
END { 
    for (key in used) { 
     if (used[key] == 0) 
      print data[key] 
    } 
} 

Примечания:

  • Сценарий использует преимущества предположения, что file2 меньше, чем file1, поскольку он использует массив onl y для нескольких записей в файле2.
  • Новые записи просто добавляются к выходу. Нет сортировки. Если это потребуется, потребуются дополнительные усилия.

EDIT

замечание

Вняв @ JonathanLeffler в о том, как определить, какой файл обрабатывается я хотел бы предложить альтернативный вариант, который может (или не может :-)) быть немного более прямой вперед, чтобы понять, чем проверка NR=FNR. Тем не менее, он работает только для достаточно последних версий awk, которые способны возвращать размер массива, как length(array):

BEGIN { 
    FS = "," 
} 
{ 
    # The following effectively creates an array entry for each filename found (for "known" filenames existing entries are overwritten). 
    files[FILENAME] = 1 
    # check the number of files we have so far 
    if (length(files) == 1) { 
     # we are still in the first file 
     date[$2] = $3 
     data[$2] = $0 
     used[$2] = 0 
    } else { 
     # we are in the second file (or any other following file) 
     if ($2 in date) { 
      used[$2] = 1 
      if ($3 < date[$2]) 
       print data[$2] 
      else 
       print $0 
     } else { 
      print $0 
     } 
    } 
} 
END { 
    for (key in used) { 
     if (used[key] == 0) 
      print data[key] 
    } 
} 

Кроме того, если вам требуется ваш выход для сортировки по второму ряду можно заменить звоните в awk этим:

awk -f script.awk input2.csv input1.csv | sort -t "," -n -k 2 > result.csv 

Последнее, конечно, работает для обеих версий скрипта.

+0

Базовая логика выглядит звуковой и очень похожей на то, что я использовал (я удаляю использованные записи из массива, у вас есть вспомогательный массив 'used' для передачи той же информации). Однако, используя два имени файла, вы делаете код очень хрупким, тогда как мой код будет работать с 'input2.csv' и' input1.csv', а также с файлами 'file2' и' file1'. В некотором смысле, идиома 'FNR == NR' не так радует, но она хорошо работает для обработки первого файла по-другому от других. –

+0

Спасибо, Маркус. Ваше решение тоже хорошо работало, как Джонатан .. :) вы рок –

Смежные вопросы