How do I replace characters only on certain lines?

I need to replace single quotes with double quotes AND double quotes with single quotes in over 600 files. I’ve been reading various topics most of the day. I am hampered by only knowing some basic shell scripting commands and an unfamiliarity with regexp.

Below is a sample file I’ve made a bit generic.

   some text KEYWORD_1 table name column = "string" AND column = "string"
    Additional text
          .
          .
          .
   some text KEYWORD_2 text 'text in quote' etc. 

I only want to change the quotes on the 2 lines with KEYWORDs. I can’t guarantee the keywords are always going to be first line and last line. I need my solution to find the keyword and change all the quotes on that line only.

I tried some things I found in sort of similar questions on this forum, including a meta on SED. I tried to figure out how to use this command: sed -i 's/foo\(.*baz\)/bar\1/' file. According to that topic the command, “Replaces foo with bar only if there is a baz later on the same line.” My keyword is not later on the same line its at the beginning and I couldn’t make it work for me.

I also tried ex -sc 'g/DEL/s/ALF/BRA/g' -cx file that didn’t do anything. I’m assuming it can’t be executed from the command line. I really don’t want to open each of 600 files.

At one point I tried, grep KEYWORD_1 file | sed -i "s/'/\"/g" file
Of course, that changed all the quotes in the file not just the one line.

I’m betting the solution is simple and I just can’t see it. How can I do this?

As requested my desired output is:

some text KEYWORD_1 table name column = 'string' AND column = 'string'
    Additional text
          . 
          .
          .
some text KEYWORD_2 text "text in quote" etc.

Here is Solutions:

We have many solutions to this problem, But we recommend you to use the first solution because it is tested & true solution that will 100% work for you.

Solution 1

Changing characters

Changing a set of characters to another set of characters is generally a task for the tr command but since you want to do it on certain lines only, it will be best done by sed which has a y command similar to tr:

sed -e "/^KEYWORD_1/  y/\"/'/" \
    -e "/^KEYWORD_2/  y/'/\"/" \
    file

Each sed command here starts with a line selector /^KEYWORD/ which instructs sed to only operate on the line matching the pattern between /. Here the patterns start with the character ^ to indicate they are to be found at the beginning of the line.

Following the line selector is sed‘s substitution command y/set1/set2/g which replaces every occurrence of a character in set1 with the character which has the same position in set2.

Swapping characters

Now, if on the same line you want to replace each " with ' and at the same time each ' with ", you can use only one command:

sed -e "/^KEYWORD_1\|^KEYWORD_2/  y/\"'/'\"/" file

Solution 2

The complication here is that if you replace all ' with " and then all " with ', you will be left with only '. So, you will first need to replace ' with something else—for example, the NULL character (\0) which you can safely assume won’t be in your input file—then " with ' and then replace that something else with " again. For example, in perl:

$ perl -pe "if(/KEYWORD){s/'/\0/g; s/\"/'/g; s/\0/\"/g}" file
KEYWORD_1 table name column = 'string' AND column = 'string'
Additional text
      .
      .
      .
KEYWORD_2 text "text in quote" etc. 

Explanation

  • -pe : print each input line after applying the script given by -e.
  • if(/KEYWORD/){something} : do something only if this line matches KEYWORD.
  • s/foo/bar/g : replace all occurrences of foo in the line with bar. The g means “global”. Without it, only the 1st occurrence on each line would be replaced.

Note that since the script itself is inside double quotes, the double quotes inside the script need to be escaped (\").


As pointed out in the comments, there’s a more direct way I should have thought of in the first place:

perl -pe "tr/'\"/\"'/ if /^KEYWORD/" file

The tr operator transliterates lists of characters. The general format is tr/searchlist/replacementlist/. So this will replace all ' with " and all " with ' only on lines matching KEYWORD.

Solution 3

Slightly crude, but working GNU awk:

$ awk -v sq="'" '/KEYWORD/{if ($0~sq){ gsub(sq,"\"")} else if ($0~"\"") gsub(/\"/,sq)};1' input.txt                      
KEYWORD_1 table name column = 'string' AND column = 'string'
Additional text
      .
      .
      .
KEYWORD_2 text "text in quote" etc.

sq variable is used to represent single quotes, since embedding it into code block itself is a bit of a pain in awk. Basic idea is that we search for pattern, if pattern is found – we make decision what to replace. Final 1 simply tells awk to print the lines.

As for outputting it to file, simply use shell’s > operator to redirect text into temporary file, and replace old file with new via mv command.

Note: Use and implement solution 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply