3

I'm trying to replace lines that match the regex => '.*', in one file with lines from another file.

Two example files.

File 1:

    'text_clear' => 'Clear',
    'text_search' => 'Search',
    'text_enabled' => 'Enabled',

File 2:

emptied
lost
turned off

I'm trying to run a linux command using awk/sed/grep to create a third file that would output

File 3:

    'text_clear' => 'emptied',
    'text_search' => 'lost',
    'text_enabled' => 'turned off',

I've been successful in extracting what I want to edit a python script, but if possible I want to just use a linux command to do both.

I've been racking my head over this for 3 hours now. Any help would be appreciated.

  • Will you at any point need to insert text such as That's all or replace such text, i.e. text that contains single quotes? What about text that contains newlines? – Kusalananda Oct 22 at 6:31
  • Can you please clarify one more point? Do all lines in file1 necessarily match? If not, it would have been a nice idea to provide a line that does not match. – Quasímodo Oct 22 at 10:26
10

code.awk:

BEGIN{j=1}
NR==FNR{a[NR]=$0;next}
sub(/=> '.*',$/,"=> '"a[j]"',"){++j}
1
awk -f code.awk file2 file1 > file3

Line by line explanation:

  • Initialize j=1.
  • Put each line of file2 in the array a.
  • In file1, for each line, try to substitute a string matching the => '.*',$ regex by the concatenation of => ' a[j] ',. If the substitution occurred, increment j.
  • Print the line.
$ cat file3
    'text_clear' => 'emptied',
    'text_search' => 'lost',
    'text_enabled' => 'turned off',
| improve this answer | |
  • 2
    I am curious: Why use "manual" counters i and j instead of simply FNR for both files? – AdminBee Oct 22 at 7:33
  • 2
    @AdminBee Well noted! i could be NR indeed, I didn't notice it when writing. But not j if we assume that there can be lines that do not match in file1. I'm assuming that is possible from the 1st sentence of the question. – Quasímodo Oct 22 at 10:16
  • Hm you are right; the sentence can be interpreted like that ... – AdminBee Oct 22 at 12:24
  • 1
    Complaint about style: you're allowed to use whitespace in your awk code. – glenn jackman Oct 22 at 14:13
  • @glennjackman Sorry about that, I don't like extra whitespace but I do have the impression that they are encouradged by many languages style guides. I'll try to keep that in mind in my future posts. – Quasímodo Oct 22 at 18:48
4

Another awk approach, using match and substr:

$ awk -v pat="'[^']*'" -v q="'" -v file2='File2' '
  BEGIN{OFS=FS=" => "}
  match($2,pat) && ((getline str < file2) > 0) {
    $2 = substr($2,1,RSTART-1) q str q substr($2,RSTART+RLENGTH)
  }
  1
' File1
    'text_clear' => 'emptied',
    'text_search' => 'lost',
    'text_enabled' => 'turned off',
| improve this answer | |
  • 1
    A GNU awk variation of this answer: gawk -v patt="(.* => ')[^']+('.*)" -v file2="File2" 'match($0, patt, m) && (getline str < file2) > 0 {$0 = m[1] str m[2]} 1' File1 – glenn jackman Oct 22 at 14:11
  • @glennjackman yeah that's nice thanks - tbh I hesitated about posting my answer because of the ugliness of dealing with quoting the replacement text (which your variant avoids cleanly) – steeldriver Oct 22 at 14:18
3

Another awk solution:

$ awk -F"'" -v OFS="'" '(getline line < "file2")==1{$4=line} 1' file1
    'text_clear' => 'emptied',
    'text_search' => 'lost',
    'text_enabled' => 'turned off',

This relies on the fact that each input line has 2 single quote characters before the field to be replaced.

If you want to replace only lines matching the => '.*', regex, then you can use:

awk -F"'" -v OFS="'" '/=> \x27.*\x27,/ && (getline line < "file2")==1{$4=line} 1' file1
| improve this answer | |
0

Here's a concise solution that uses paste and sed:

$ cat file1
    'text_clear' => 'Clear',
    'text_search' => 'Search',
    'text_enabled' => 'Enabled',
$ cat file2
emptied
lost
turned off
$ paste file1 file2 | sed 's/=> \'.*\',\t\(.*\)/=> \'\1\',/'
    'text_clear' => 'emptied',
    'text_search' => 'lost',
    'text_enabled' => 'turned off',
| improve this answer | |

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