Jimmy
Jimmy

Reputation: 12487

Awk replace entire line when match is found

I have the following code:

function replaceappend() {
    awk -v old="^$2" -v new="$3" '
        sub(old,new) { replaced=1 }
        { print }
        END { if (!replaced) print new }
    ' "$1" > /tmp/tmp$$ &&
    mv /tmp/tmp$$ "$1"
}

replaceappend "/etc/ssh/sshd_config" "Port" "Port 222"

It works perfectly but I am looking to modify it so it replaces the entire lines contents rather than just the matching text.

At the moment it would do this:

Port 1234 -> Port 222 1234

I want it to be work like this:

Port 1234 -> Port 222

I closest code I can find to do this is found here:

awk 'NR==4 {$0="different"} { print }' input_file.txt

This would replace the entire line of the match with the new content. How can I implement this into my existing code?

Upvotes: 0

Views: 4414

Answers (3)

Tom Fenech
Tom Fenech

Reputation: 74596

If you want to replace the entire line you can simplify your function. To avoid problems with metacharacters in the variables you pass to awk, I would suggest using a simple string search too:

awk -vold="$2" -vnew="$3" 'index($0,old)==1{f=1;$0=new}1;END{if(!f)print new}' "$1"

index returns the character position of the string that you are searching for, starting at 1. If the string old is at the start of the line, then the line is changed to the value of new. The 1 after the block is always true so every line is printed (this is a common shorthand for an unconditional {print} block).

As mklement0 has pointed out in the comments, the variables you pass to awk are still subject to some interpretation: for example, the string \n will be interpreted as a newline character, \t as a tab character, etc. However, this issue is much less significant than it would be using regular expressions, where things like a . would match any character.

Upvotes: 2

Ed Morton
Ed Morton

Reputation: 203169

Just change:

sub(old,new) { replaced=1 }

to:

$0~old { $0=new; replaced=1 }

or:

sub(".*"old".*",new) { replaced=1 }

Upvotes: 3

jas
jas

Reputation: 10865

Again, use a regular expression for that which you want to replace:

replaceappend port.txt "Port.*" "Port 222"

Here you are replacing Port (if it starts the line, as per your function definition) plus whatever follows until the end of the line with "Port 222".

EDIT: To make this part of the function instead of requiring it in the call, modify it to

function replaceappend() {
    awk -v old="^$2.*" -v new="$3" '                                                                                                        
        sub(old,new) { replaced=1 }                                                                                                         
        { print }                                                                                                                           
        END { if (!replaced) print new }                                                                                                    
    ' "$1" > /tmp/tmp$$ &&
    mv /tmp/tmp$$ "$1"
}

Upvotes: 1

Related Questions