tac file |
awk -v string='apple1' -v replace='444444444' '
!flag && $1 == string { $3 = replace; flag = 1 }
{ print }' |
tac
Этот конвейер сначала меняет порядок строк в данных, используя tac
из GNU coreutils. Последняя строка, где 1-й столбец представляет собой определенную строку, легче найти таким образом.
Команда awk
просто сравнивает первый столбец с заданной строкой, и если мы еще не сделали замену(!flag
не -ноль ), мы изменяем третий столбец, как только мы найти строку в 1-м столбце. При этом мы также устанавливаем flag
в единицу, чтобы не производить дальнейших замен.
Остальная часть программы awk
просто печатает текущую строку (, включая измененную ).
В конце конвейера мы снова меняем порядок строк с помощью tac
.
Результатом этого, учитывая данные в вопросе, является
apple1 10109283 20012983
apple1 10983102 10293809
apple1 10293893 444444444
apple10 109283019 109238901
apple10 192879234 234082034
apple10 234908443 3450983490
Столбцы в измененной строке немного отличаются от столбцов в других строках из-за модификации 3-го столбца. Чтобы он выглядел лучше, вы можете пропустить результат через дополнительную стадию column -t
в конце конвейера. Если вы это сделаете, вывод будет выглядеть как
apple1 10109283 20012983
apple1 10983102 10293809
apple1 10293893 444444444
apple10 109283019 109238901
apple10 192879234 234082034
apple10 234908443 3450983490
с несколькими пробелами между столбцами.
С sed
это не так просто, как просто заменить 3-й столбец в первой строке, где строка встречается в 1-м столбце (, предполагая, что мы меняем местами строки данных, как в приведенном выше конвейере ). Мы также должны не заменять 3-й столбец в любых последующих строках, даже если 1-й столбец соответствует нашей строке.
Это sed
сценарий редактирования, который делает это правильно (может быть любое количество его вариантов, которые могут работать):
/^apple1\>/ ! {
p
d
}
s/[[:digit:]]*$/444444444/
:loop
n
$ ! b loop
Первая часть заботится о печати строк в начале ввода, которые не соответствуют apple1
в первом столбце.\>
в выражении соответствует концу слова apple1
, так что мы случайно не найдем apple10
или apple12
или любую другую подобную строку.p
(print )иd
(delete + continue со следующей строкой сверху скрипта )внутри {... }
выполняются для каждой строки в начале ввода, которая не . ] соответствует выражению.
Команда s
(замена )выполняется для первой строки ввода, в которой соответствует apple1
в начале строки. Он просто заменяет строку цифр в конце строки на наши 4
s.
Затем следует секция с меткой loop
, которая заботится о передаче остальных данных без изменений путем печати текущей строки и чтения следующей строки с помощьюn
(n
выполняет как печать, так и чтение ). «Текущая строка» будет изменена командой s
при первом проходе по этому циклу.
Самая последняя строка возвращается к метке loop
, если мы еще не достигли последней строки ввода.
Пример запуска:
$ tac file | sed -f script.sed | tac
apple1 10109283 20012983
apple1 10983102 10293809
apple1 10293893 444444444
apple10 109283019 109238901
apple10 192879234 234082034
apple10 234908443 3450983490