简体   繁体   中英

If string is found in line, replace with string from previous line, sed

I have a few thousand lines of code spread out across multiple files that I need to update. Right now they are like so:

active_data(COPIED),

I need to replace all instances of COPIED (only in these lines) with the text inside the parenthesis on the previous line. So it total the code currently might look like:

current_data(FOO|BAR|TEXT),
active_data(COPIED),

and I want it to look like:

current_data(FOO|BAR|TEXT),
active_data(FOO|BAR|TEXT),

I can find the lines to be replaced easily enough, and could replace the with some static string with no problem, but I'm not sure how to pull the data from the previous line and use that. I'm sure its pretty simple but can't quite figure it out. Thanks for the help.

(I could see using AWK or something else for this too if sed won't work but I figure sed would be the best solution for a one time change).

sed could work but awk is more natural:

$ awk -F'[()]' '$2 == "COPIED" {sub(/COPIED/, prev)} {prev=$2;} 1' file
current_data(FOO|BAR|TEXT),
active_data(FOO|BAR|TEXT),
  • -F'[()]'

    Use open or claose parens as the field separator.

  • $2 == "COPIED" {sub("COPIED", prev)}

    If the second field is COPIED , then replace it with prev .

  • prev=$2

    Update prev .

  • 1

    This is cryptic shorthand which means print the line. It is equivalent to {print $0;} .

How awk sees the fields

$ awk -F'[()]' '{for (i=1;i<=NF;i++)printf "Line %s Field %s=%s\n",NR,i,$i;}' file
Line 1 Field 1=current_data
Line 1 Field 2=FOO|BAR|TEXT
Line 1 Field 3=,
Line 2 Field 1=active_data
Line 2 Field 2=COPIED
Line 2 Field 3=,

Changing in-place all files in a directory

for file in *
do
  awk -F'[()]' '$2 == "COPIED" {sub("COPIED", prev)} {prev=$2;} 1' "$file" >tmp$$ && mv tmp$$ "$file"
done

Or, if you have a modern GNU awk:

awk -i inplace -F'[()]' '$2 == "COPIED" {sub("COPIED", prev)} {prev=$2;} 1' *

This might work for you (GNU sed):

sed 'N;s/\((\([^)]*\)).*\n.*(\)COPIED/\1\2/;P;D' file

This keeps a moving window of 2 lines open throughout the length of the file and uses pattern matching to effect the required result.

With GNU awk for FPAT:

$ awk -v FPAT='[(][^)]*[)]|[^)(]*' -v OFS= '$2=="(COPIED)"{$2=prev} {prev=$2; print}' file
current_data(FOO|BAR|TEXT),
active_data(FOO|BAR|TEXT),

With other awks:

$ awk '
match($0,/\([^)]*\)/) {
    curr = substr($0,RSTART,RLENGTH)
    if (curr == "(COPIED)") {
        $0 = substr($0,1,RSTART-1) prev substr($0,RSTART+RLENGTH)
    }
    else {
        prev = curr
    }
}
{ print }
' file
current_data(FOO|BAR|TEXT),
active_data(FOO|BAR|TEXT),

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM