Conga
Conga

Reputation: 115

Replacing value with value in a second file

I have two files. Both files are a TXT.

File one contains strings, one per line.

File two contains some text.

File two looks like this:

 title:
  VALUE:
    display_name: VALUE
    resource:
      material: material
      generate: false
      model_path: model/VALUE
 title:
  VALUE:
    display_name: VALUE
    resource:
      material: material
      generate: false
      model_path: model/VALUE

File one like this:

einundzwanzig
dreiundzwanzig
vierundzwanzig
fuenfundzwanzig

My intention is, that VALUE gets replaced with the string in line one, for three times. Then for the next three VALUEs the second string. And so on. I tried to get it done by using bash, but it doesn't work out.

So I tried following script:

    count=1
# filetwo.txt is your file
cat test.xml | tr "\n" "\t" > test2.xml
while read line
do
    echo $count
    echo $line
    sed -i " s_value[^<]*value_value$linevalue_${count}; " fileone.txt
    ((count++))
done < filetwo.txt
cat test2.xml | tr "\t" "\n" >fileoutput.txt

But it does not want to work :(

Upvotes: 0

Views: 63

Answers (2)

potong
potong

Reputation: 58578

This might work for you (GNU sed):

sed -Ee '1{x;s/^/cat file1/e;x}                     # copy file1 to hold space
         :a;/title:/{                               # when line contains title:
           :b;n;/title:/{x;s/^[^\n]*\n//;x;ba}      # end of stanza reduce file1
           /VALUE/{G;s/VALUE([^\n]*)\n(\S+).*/\2\1/} # replace VALUE 
         bb}' file2                                 # repeat

On line one, copy the contents of file1 into the hold space.

If a line contains title: print that line and fetch the next.

If that line contains title, remove the first line of file1 in the hold space and repeat from loop holder :a.

Otherwise, if the current line contains VALUE, append the hold space to the current line and replace VALUE by the first line in the hold space.

Repeat from loop holder :b.

Alternative, just replace 3 VALUE fields in file2 for each line in file1:

sed -E '1{x;s/^/sed "p;p" file1/e;x}
        :a;/VALUE/{G;s/VALUE([^\n]*)\n(\S+).*/\2\1/;x;s/[^\n]*\n//;x;ba}' file2

Upvotes: 2

markp-fuso
markp-fuso

Reputation: 35556

Assumptions:

  • we are looking to replace the literal strings VALUE
  • the literal string VALUE does not show up in a longer string (eg, DEVALUE)
  • the number of VALUE strings is less than (or equal) to three times the number of replacement strings (ie, we won't run out of replacement strings)

Input files:

$ cat value.template
 title:
  VALUE:
    display_name: VALUE
    resource:
      material: material
      generate: false
      model_path: model/VALUE
 title:
  VALUE:
    display_name: VALUE
    resource:
      material: material
      generate: false
      model_path: model/VALUE
 title:
  VALUE:
    display_name: VALUE
      model_path: model/VALUE
 title:
  VALUE:
    display_name: VALUE
      model_path: model/VALUE

$ cat value.dat
einundzwanzig
dreiundzwanzig
vierundzwanzig
fuenfundzwanzig

One awk solution:

awk '
BEGIN   { i=1 }                                    # initialize our array counter

# process first file (NR==FNR)

NR==FNR { v[i++]=v[i++]=v[i++]=$1 ; next }         # save the replacement string in next 3 array slots

# process second file

FNR==1  { i=1 }                                    # for first line of 2nd file, reset our array counter
/VALUE/ { while ( sub("VALUE",v[i]) ) { i++ } }    # if line includes "VALUE" string then replace each occurrence with next array element referenced by "i"; increment i for next sub()/match
        { print }                                  # print current line
' value.dat value.template

A different awk solution that stores the replacement strings just once in the v[] array:

awk '
BEGIN   { i=0 }                                              # initialize array counter
NR==FNR { v[i++]=$1 ; next }                                 # save the replacement string in next array slot
FNR==1  { i=1 }                                              # for first line of 2nd file, reset our array counter
/VALUE/ { while ( sub("VALUE",v[int((i-1)/3)]) ) { i++ } }   # for every 3 instances of "VALUE" replace with the same entry from the v[] array; increment i after each sub()/match
        { print }                                            # print current line
' value.dat value.template

NOTE: Remove comments to declutter code

Both of the above generate:

 title:
  einundzwanzig:
    display_name: einundzwanzig
    resource:
      material: material
      generate: false
      model_path: model/einundzwanzig
 title:
  dreiundzwanzig:
    display_name: dreiundzwanzig
    resource:
      material: material
      generate: false
      model_path: model/dreiundzwanzig
 title:
  vierundzwanzig:
    display_name: vierundzwanzig
      model_path: model/vierundzwanzig
 title:
  fuenfundzwanzig:
    display_name: fuenfundzwanzig
      model_path: model/fuenfundzwanzig

Upvotes: 2

Related Questions