I want to modify a line if a specific keyword is found in a line.


In above line, if 'PORT_NUM' is present then 'BILL_NO' should be replaced with 'NA'. Only the keyword present in the line should be replaced.

I am using below approach:

while IFS=$'\n' read -r line
     if [[ $line == *"$string"* ]]; then
           < sed command to replace only keyword >
done < "$file"

How can I achieve this?

Note: '-i' extension does not work in my sed version.

  • 1
    sed '/PORT_NUM/ s/BILL_NO/NA/' >new_file... – jasonwryan Mar 31 '15 at 7:47
  • jasonwryan; I'm curious, why you posted your solution as comment and not as answer? – Janis Mar 31 '15 at 7:56
  • @Janis It was a drive by: I am pretty sure this is a duplicate, I have been looking for a match... – jasonwryan Mar 31 '15 at 8:04
  • 1
    @jasonwryan true *nix thug for life dawg, drive by sed answers... – Nathan McCoy Mar 31 '15 at 11:39

Menon, you got already a sed answer how to do the operation on the whole file. If your intention is to work on individual lines, as shown in your code frame, then you don't need sed (or any other external program), since your shell can likely (see note below) do the substitution. Assuming variable string in your code contains (e.g.) the value PORT_NUM, the replacement in the line variable could be done by:

while read line
     if [[ $line =~ $string ]]; then
done < "$file"

(Note: This substitution works with contemporary shells, like bash, ksh, zsh.)

| improve this answer | |
  • This will elide $IFS at the head and tail of each line and interpret backslash escapes in input. $line here is not literally a line from "$file" but is rather the shell's interpretation of said line. In the same vein, $string is not a literal representation of a string to match but is rather the shell's interpretation of one (or many) strings. – mikeserv Mar 31 '15 at 8:50
  • 1
    @mikeserv; your comment should certainly be put on the question! This answer is addressing the replacement, which was the OP's question, and the code frame around it taken from the original question so that he can easily see where the changes are. If I'd intend to write a solution for the OP's complete task I'd not only do the usual while IFS= read -r line, but avoid the whole shell loop. – Janis Mar 31 '15 at 8:56
  • @mikeserv; your comment "string is not a literal representation of a string to match but is rather the shell's interpretation" is strange; what do you mean here? To me string is, as I've written, a variable, whose value $string can (WRT the OP's description) here be, e.g., the pattern "PORT_NUM" to which the string(-value) is to be compared to. Please explain any issues you have with that. – Janis Mar 31 '15 at 9:12
  • Well, I mean that an unquoted var on the right hand side is a pattern and not a string. If it is just numbers then it is likely safe, but there's not validation here and so you can't know. The shell is definitely treating it as a pattern whether it is just numbers or not - except that if it is then it is a pattern which will match only one string - itself. Basically, try string=* then [[ $line =~ $string ]] and [[ $line =~ "$string" ]]. – mikeserv Mar 31 '15 at 9:23
  • @mikeserv, I see where you're comming from. Though, if the OP is searching for specific keyword patterns (like "PORT_NUM") in the lines of the file I don't see where the regexp meta-characters should come from. That said, I agree that there's quite some potential to make the snippet more robust, specifically for other application contexts, e.g. where the content of string contains uncontrolled user input, but (as already mentioned) there's likely a more appropriate way to solve the overall task anyway, so I'll try to stay focussed on the basic question asked. – Janis Mar 31 '15 at 9:43

Not the answer you're looking for? Browse other questions tagged or ask your own question.