Вопрос или проблема
Мне нужно редактировать строку “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
зависит от ваших предпочтений и условий среды, в которой вы работаете.
Эти команды помогут вам аккуратно обработать данные в файлах, не нарушая их структуры и обеспечивая точность в редактировании. Если у вас есть дополнительные вопросы или требуется помощь с другими сценариями, не стесняйтесь обращаться за поддержкой.