Возможно ли иметь различное поведение для первого и второго входных файлов для awk?

Например, предположим, что я запускаю следующую команду:

gawk -f AppendMapping.awk Reference.tsv TrueInput.tsv

Предположим, что имена файлов БУДУТ изменены. Перебирая первый файл, я хочу создать сопоставление.

map[$16]=$18

При повторении второго файла я хочу использовать сопоставление.

print $1, map[$2]

Каков наилучший способ добиться такого поведения (т. е. различного поведения для каждого входного файла)?


person merlin2011    schedule 21.05.2012    source источник


Ответы (3)


Как вы, наверное, знаете, NR хранит текущий номер строки; как вы можете знать или не знать, он кумулятивный - он не сбрасывается между файлами. FNR, с другой стороны, зависит от файла, поэтому вы можете использовать эти два, чтобы увидеть, находитесь ли вы в первом файле (после второго вам нужно будет сохранить свой собственный счетчик).

# In case you want to keep track of the file number
FNR == 1 { fileno++ }*emphasized text*

NR == FNR {
    # First file
}
NR != FNR {
    # Second or later file
}

Вы также можете использовать getline в блоке BEGIN, чтобы перебрать его вручную.

BEGIN {
    file = ARGV[1]
    while(getline < file) {
        # Process line
    }
    delete ARGV[1]
}
person Kevin    schedule 21.05.2012
comment
Часто в цикле NR == FNR последним оператором является next. Когда это используется, нет необходимости в NR != FNR, и, таким образом, другие условия селектора упрощаются. - person Dennis Williamson; 21.05.2012

Версия Gawk 4 и выше предлагает специальный блок BEGINFILEENDFILE), а также обычные блоки BEGIN и END. Используйте их для установки флагов, которыми вы меняете поведение своего кода.

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

На странице руководства говорится:

Для каждого входного файла, если существует правило BEGINFILE, gawk выполняет соответствующий код перед обработкой содержимого файла. Точно так же gawk выполняет код, связанный с ENDFILE, после обработки файла.

person dmckee --- ex-moderator kitten    schedule 21.05.2012
comment
Это доступно только с GAWK 4. - person Dennis Williamson; 21.05.2012
comment
@ Деннис Уильямсон Спасибо. В текст добавлены ограничения версий. - person dmckee --- ex-moderator kitten; 21.05.2012

Это может сработать для вас:

seq 5 >/tmp/a
seq 100 105 >/tmp/b
awk 'FILENAME==ARGV[1]{print FILENAME,$0};FILENAME==ARGV[2]{print $0,FILENAME}' /tmp/{a,b}
/tmp/a 1
/tmp/a 2
/tmp/a 3
/tmp/a 4
/tmp/a 5
100 /tmp/b
101 /tmp/b
102 /tmp/b
103 /tmp/b
104 /tmp/b
105 /tmp/b

Таким образом, комбинируя FILENAME с ARGV[n], где n — это n-й файл в командной строке, awk может условно изменять отдельные файлы.

Н.Б. ARGV[0] будет командой awk.

person potong    schedule 21.05.2012