0

I have tried to search for last occurrence in a file using sed. In HP-UX tac option is not available.

For Ex: Below is the data in file,

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|

I'm trying:

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

It is changing from 00001148 to 00001147 for both the occurrence of 00001148.

I have to search for |00001148| of last occurrence and replace with another number. Currently my sed command is changing both two instances of 00001148.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Srinivas
  • 21
  • 1
  • 1
  • 5
  • Is the matching line last line in the file?? – nu11p01n73R Oct 08 '14 at 04:41
  • yes, my command is matching and replacing with 00001147 in both first and last line. But I want to change only in last matching line. – Srinivas Oct 08 '14 at 04:46
  • Note that the use of `cat` is completely UUOC — Useless Use of `cat`. `sed` is perfectly capable of reading files. – Jonathan Leffler Oct 08 '14 at 05:41
  • Is it guaranteed that the line to be replaced is the last line, or could there be many other lines both before and after the repeated number that needs fixing? How big is the data file? In the absence of `tac` (can't you simply install it?), there are ways to reverse a file that work on smaller files that'll fit in memory and others that work on larger files that won't fit in memory. – Jonathan Leffler Oct 08 '14 at 06:05

4 Answers4

7

EDIT

To match the last line, use $

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

will give the output as

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|

If the matching line is the last line in the file, use tail instead of cat

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

The tail command selects the last(tail) lines form the file, here it is specified to take 1 line usint -1 option

if it is not the last line,

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

The grep command finds all the occureences and tail selects the last line and sed makes the replacement.

nu11p01n73R
  • 26,397
  • 3
  • 39
  • 52
  • Both commands will get only 1 line with the replaced string 00001147, but i need remaining data in the file with the replaced string. So do i need to replace the last line with the output of the line from the above command? – Srinivas Oct 08 '14 at 05:03
  • I have tried sed '$s/00001148/00001147/g' $filename, but not replacing the last occurrence of a string. But i have changed something like this, sed "5,$ s/00001147/00001146/g" $filename. It is searching for pattern and replacing in 5th line. – Srinivas Oct 08 '14 at 05:52
  • Your input is not clear. `$` substitutes IF THERE IS AN OCCURENCE in last line. if not it doesnt do anything. As of `5,$` it replacess all occurences between 5th line and last line, if it replaces your 5th line then it occures only at 5th line – nu11p01n73R Oct 08 '14 at 06:05
0

Way with awk and sed

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

Can probs all be done in sed though

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

sed is trying to get the biggest content in search pattern, so by default form start to the last |00001148| is the biggest pattern available (if any)

NeronLeVelu
  • 9,908
  • 1
  • 23
  • 43
0

Try this:

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

tac inverts your file.
The sed command replaces the first occurrance.
Then use tac again to invert the result.

Mauro Zallocco
  • 196
  • 1
  • 3