Как редактировать строку, соответствующую шаблону в определенном поле, при условии, что другая строка отсутствует на той же строке

Вопрос или проблема

Мне нужно редактировать строку “NA” на “Na” только в том случае, если она находится в 6-м поле файла. В данный момент я могу сделать это следующим образом:

awk '{gsub("NA","Na",$6)}1' $filename

Однако мне нужно дополнительное условие, что это не произойдет, если строка “HEM” находится в той же строке. Например, я бы хотел, чтобы следующая строка осталась без изменений:

7353  NA       5.4433   24.4404   -3.0784 NA    456  HEM 

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

Я думаю, это можно сделать с помощью чтения файла построчно и печати каждой строки, редактируя только с помощью оператора if, но я стараюсь избежать чего-то громоздкого.

Мне кажется, что это довольно сложная задача выполнить простым способом, но я был бы очень благодарен, если бы какие-либо unix-волшебники знали, как это сделать. Спасибо!

Используя GNU awk для третьего аргумента к match() и \s/\S шорткоды:

awk '!/HEM/ && match($0,/^((\S+\s+){5})NA(\s.*)/,a){ $0=a[1] "Na" a[3] } 1' file

или используя любой POSIX awk:

awk '!/HEM/ && match($0,/([^[:space:]]+[[:space:]]+){5}NA[[:space:]]/){ $0=substr($0,1,RLENGTH-3) "Na" substr($0,RLENGTH) } 1' file

Ответ или решение

Для редактирования строки с определенным паттерном в конкретном поле (в данном случае, в шестом поле) файла, тогда как другое строковое значение (например, "HEM") отсутствует в той же строке, можно воспользоваться утилитой awk. Это решение позволит вам не только выполнить замену "NA" на "Na", но и предотвратить изменение строк, содержащих "HEM".

Решение с использованием awk

Вы можете использовать следующую команду awk, которая эффективно выполняет поставленную задачу, сохраняя при этом исходный формат полей и отступы:

awk '!/HEM/ && match($0, /^((\S+\s+){5})NA(\s.*)/, a) { $0 = a[1] "Na" a[3] } 1' filename

Пояснение команды:

  • !/HEM/: Эта часть гарантирует, что строки, содержащие "HEM", будут пропущены.
  • *`match($0, /^((\S+\s+){5})NA(\s.)/, a)**: Функцияmatchищет совпадение для регулярного выражения, которое определяет строки, состоящие из пяти полей (разделенных пробелами), после которых следует "NA" в шестом поле. Если совпадение найдено, результат сохраняется в массивеa`.
  • $0 = a[1] "Na" a[3]: Если совпадение прошло успешно, шестое поле заменяется на "Na", при этом первое и третье подмножества массива a содержат остальную часть строки.
  • 1: Это является эквивалентом print $0, что выводит измененную или неизмененную строку.

Альтернативное решение для POSIX awk

Если вы желаете использовать POSIX-совместимый awk, можно применить следующее:

awk '!/HEM/ && match($0, /([^[:space:]]+[[:space:]]+){5}NA[[:space:]]/) { $0 = substr($0, 1, RLENGTH - 3) "Na" substr($0, RLENGTH) } 1' filename

Пояснение этого решения:

  • Используется аналогичный подход для определения строк без "HEM" и замены "NA" на "Na" в шестом поле, однако здесь применяется POSIX-совместимый синтаксис.

Заключение

Оба решения позволяют эффективно удовлетворить требования задачи: заменять "NA" на "Na" в шестом поле без изменения строк, содержащих "HEM", и при этом сохранять форматирование полей. Выбор между использованием GNU awk или POSIX awk зависит от ваших предпочтений и условий среды, в которой вы работаете.

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

Оцените материал
Добавить комментарий

Капча загружается...