KSH: команда sed для поиска и замены последнего вхождения строки в файле

Я попытался найти последнее вхождение в файле, используя sed. В HP-UX опция tac недоступна.

Например: Ниже приведены данные в файле,

A|2121212|666666666 | 2|01|2 |B|1111111111 |234234234 |00001148|
B|2014242|8888888888| 3|12|3 |B|22222222222 |45345345 |00001150|
C|4545456|4444444444| 4|31|4 |B|3333333333333 |4234234 |00001148|

Я пытаюсь:

cat $filename | sed 's/00001148/00001147/g'

Он меняется с 00001148 на 00001147 для обоих вхождений 00001148.

Мне нужно найти |00001148| последнего вхождения и заменить другим номером. В настоящее время моя команда sed изменяет два экземпляра 00001148.


person Srinivas    schedule 08.10.2014    source источник
comment
Является ли совпадающая строка последней строкой в ​​файле??   -  person nu11p01n73R    schedule 08.10.2014
comment
да, моя команда соответствует и заменяет 00001147 как в первой, так и в последней строке. Но я хочу изменить только последнюю совпадающую строку.   -  person Srinivas    schedule 08.10.2014
comment
Обратите внимание, что использование cat полностью UUOC — бесполезное использование cat. sed прекрасно умеет читать файлы.   -  person Jonathan Leffler    schedule 08.10.2014
comment
Гарантируется ли, что заменяемая строка является последней строкой, или может быть много других строк как до, так и после повторяющегося числа, которое необходимо исправить? Насколько велик файл данных? В отсутствие tac (вы не можете просто установить его?) существуют способы реверсирования файла, которые работают с меньшими файлами, которые помещаются в память, и другие, которые работают с большими файлами, которые не помещаются в памяти.   -  person Jonathan Leffler    schedule 08.10.2014


Ответы (4)


ИЗМЕНИТЬ

Чтобы соответствовать последней строке, используйте $

sed '$s/00001148/00001147/g' $filename 

выдаст результат как

A|2121212|666666666 | 2|01|2 |B|1111111111 |234234234 |00001148|
B|2014242|8888888888| 3|12|3 |B|22222222222 |45345345 |00001150|
C|4545456|4444444444| 4|31|4 |B|3333333333333 |4234234 |00001147|

Если совпадающая строка является последней строкой в ​​файле, используйте tail вместо cat

tail -1 $filename | sed 's/00001148/00001147/g'

Команда tail выбирает последние (хвостовые) строки из файла, здесь указано, что нужно взять 1 строку с опцией -1

если это не последняя строка,

   grep "00001148" $filename | tail -1 | sed 's/00001148/00001147/g'

Команда grep находит все вхождения, tail выбирает последнюю строку, а sed производит замену.

person nu11p01n73R    schedule 08.10.2014
comment
Обе команды получат только 1 строку с замененной строкой 00001147, но мне нужны оставшиеся данные в файле с замененной строкой. Так мне нужно заменить последнюю строку выводом строки из приведенной выше команды? - person Srinivas; 08.10.2014
comment
Я пробовал sed '$s/00001148/00001147/g' $filename, но не заменял последнее вхождение строки. Но я изменил что-то вроде этого, sed 5,$ s/00001147/00001146/g $filename. Ищет шаблон и заменяет в 5-й строке. - person Srinivas; 08.10.2014
comment
Ваш ввод не ясен. $ заменяет ЕСЛИ В ПОСЛЕДНЕЙ строке ЕСТЬ ПРОИСШЕСТВИЕ. если нет, то ничего не делает. Начиная с 5,$ он заменяет все вхождения между 5-й строкой и последней строкой, если он заменяет вашу 5-ю строку, то это происходит только в 5-й строке - person nu11p01n73R; 08.10.2014

Путь с awk и sed

sed '1!G;h;$!d' file | awk '/00001148/&&!x{sub("00001148","00001147");x=1}1' | sed '1!G;h;$!d'

Может ли все это быть сделано в sed, хотя

person Community    schedule 08.10.2014

sed -n '1!H;1;h;${x;s/\(.*\|\)00001148\|/&OtherNumberHere\|/;p;}' YourFile

sed пытается получить самый большой контент в шаблоне поиска, поэтому по умолчанию форма начинается с последнего |00001148| это самый большой из доступных шаблонов (если есть)

person NeronLeVelu    schedule 21.10.2014

Попробуй это:

    tac $filename | sed '0,/00001148/{s/00001148/00001147/}' | tac

tac инвертирует ваш файл.
Команда sed заменяет первое вхождение.
Затем снова используйте tac, чтобы инвертировать результат.

person Mauro Zallocco    schedule 06.09.2020