2013-09-10 4 views
1

У меня есть три файла, и я бы хотел использовать awk для сравнения первых двух, а затем обновить последний с именами, которые не совпадают с файлом frist.Сравнение трех файлов в Awk

Файл 1: ignore.txt

bob 
diana 

Файл 2: list.txt

alice 
bob 
chris 
diana 
elvis 

Файл 3: names.txt

alice 
chris 
elvis 

Файл 2 будет иметь новые имена добавлены каждый раз, так что я должен быть в состоянии сравнить его с обоими другими файлами и добавить любые новые имена в этот список в names.txt.

Это мой сценарий до сих пор, сравнение List и ignore работает, но оно не делает обновление, потому что я до сих пор не понимаю, как использовать getline и сравнить новый массив с файлами в памяти.

Я вызываю скрипт как: awk -f compare ignore.txt list.txt, и он работает. Если я вызываю его с дополнительной переменной, он не делает этого: awk -f compare -v newnames=1 ignore.txt list.txt.

BEGIN { 
    file="list.txt" 
    tmpfile="new_list.txt" 
    } 
# working 
FNR == NR { names[$0]++; next } 
!names[$0] { 
    print > names.txt 
} 
{ #not working 
if (newnames == 1) { 
    mvcmd="mv " tmpfile file; 
    while ((getline newnames < file) > 0) 
     newnames[$0]++; next 
    !newnames[$0]; 
     print > tmpfile 
    system(mvcmd) 
    close(dbfile) 
    } 

Как я могу заставить его работать? Код не очень хорош, потому что я нахожу его запутанным. Сожалею.

+0

Если заказ не важен, вы можете полностью игнорировать содержимое 'file3'. –

+0

Существует очень мало оснований для использования getline. Убедитесь, что вы прочитали и ПОЛНОСТЬЮ понимаете все подводные камни, описанные в http://awk.info/?tip/getline, если вы планируете использовать его. –

ответ

2

Это очень распространенное использование awk:

$ awk 'FNR==NR{a[$0];next}!($0 in a)' file1 file2 
alice 
chris 
elvis 

Это легче просто переписать всю file3 затем просто обновить его:

$ awk 'FNR==NR{a[$0];next}!($0 in a)' file1 file2 > file3 

Объяснение:

NR - awk переменная, увеличиваемая после каждой записи, FNR похожа, но сбрасывается до 1 каждый раз, когда считывается новый файл. NR==FNR может быть истинным только при чтении первого файла. При чтении первого файла мы создаем массив a, где ключи в массиве являются строками в файле, а также сохраняют все строки из файла1, что приведет к удалению любых дубликатов. next - это команда, которая гарантирует, что никакие дополнительные блоки не будут выполнены в текущей записи. Как только file1 был прочитан, мы просто проверяем, находится ли текущая строка в file2 в массиве (например, в file1). Условие !($0 in a) не имеет блока для выполнения, поэтому по умолчанию awk выполнено {print $0}.

В вашем сценарии много ошибок, лучше всего было бы прочитать Effective Awk Programming, если вы хотите узнать awk.

+0

Спасибо за детали. Я читаю книгу Awk, но я думаю, мне нужно попробовать написать несколько сценариев, чтобы учиться правильно. – Edouard

2

Вот способ сделать это с помощью grep:

Это будет работать, даже если names.txt не существует, чтобы начать с. (Конечно, было бы обновить names.txt если новые дополнения сделаны list.txt и команда выполняется снова.)

+0

Спасибо. Но я пытаюсь научиться awk. Но я голосовал за это. – Edouard

+1

Обратите внимание, что если имя 'ed' существует в' ignore.txt', то указанное выше будет игнорировать 'ted',' fred' и т. Д., Если они появились в 'list.txt'. –

2

Это то, что вам нужно, учитывая то, как вы описываете проблему:

awk 'FILENAME!=ARGV[3]{seen[$0]++;next} !seen[$0]++' file1 file3 file2 

Чтобы обновить file3 с выходом:

awk 'FILENAME!=ARGV[3]{seen[$0]++;next} !seen[$0]++' file1 file3 file2 >> file3 

Он будет даже удалить дубликаты новые имена из file2:

Если все значения в файле3 также существуют в файле2, но возможны дубликаты в файле2, то t его все, что вам нужно:

awk 'NR==FNR{seen[$0]++;next} !seen[$0]++' file1 file2 > file3 

Если все значения в file3 также существуют в file2 и дубликатами в file2 не представляется возможным, @ решение sudo_O будет работать нормально.

+0

Спасибо Эд. Я изучу еще кое-что. – Edouard

+0

Я думаю, что теперь я понимаю ваше решение лучше, а expet отключает FILENAME: не возражаете ли вы объяснить, как это работает? – Edouard

+0

Я не отключаю FILENAME. Все, что я делаю с FILENAME, проверяет его значение, поэтому скрипт может делать что-то другое, когда FILENAME соответствует 3-му аргументу скрипту, то есть 'file2', по сравнению с первыми 2 аргументами/файлами. –

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