2

For example, the only thing in file.txt looks like this:

xxxxxxxxxHAHAxxxxxxHOHOxxxxxxx  

I hope to replace HAHA with seq 1 3 and replace HOHO with seq 5 7, so the output should be:

xxxxxxxxx1xxxxxx5xxxxxxx   
xxxxxxxxx2xxxxxx6xxxxxxx   
xxxxxxxxx3xxxxxx7xxxxxxx   

What I did:

for i in $(seq 1 3)    
do  sed "s/HAHA/$i/g" file.txt   
  for i in $(seq 5 7)    
  do sed "s/HOHO/$i/g" file.txt   
  done   
done > new.txt     

But new.txt doesn't show what I expected. How should I change the code?

XYZ
  • 27
  • By the way, I added four spaces to each line of my code, but it doesn't format like what it should be like – XYZ Mar 04 '19 at 01:58

2 Answers2

2

Here's one way you could do it, using the bash built-in read command's ability to read from different file descriptors:

while read -u3 i && read -u4 j; do 
    sed -e "s/HAHA/$i/" -e "s/HOHO/$j/" file.txt
done > new.txt 3< <(seq 1 3) 4< <(seq 5 7)

Since your numbers have a simple arithmetic relationship, it would be simpler to use a single seq process + some shell arithmetic:

for i in $(seq 1 3); do
  sed -e "s/HAHA/$i/" -e "s/HOHO/$((i+4))/" file.txt
done > new.txt

In either case, see Why is using a shell loop to process text considered bad practice? - the inefficiencies may not matter for the minimal example you have provided, but if you are doing anything more serious you should consider using a different approach.

steeldriver
  • 81,074
2

Without calling an external utility for each line produced:

read template <file

paste <(seq 1 3) <(seq 5 7) |
while read x y; do
    t=${template/HAHA/$x}
    t=${t/HOHO/$y}
    printf '%s\n' "$t"
done >new.txt

This first reads the line from the file called file into $template. It then constructs a two-column input for a while read loop. The input to the loop is the two columns of numbers from seq.

In the loop, some bash-specific substitutions are performed on the value of $template to replace the HAHA and HOHO string with the numbers read from paste. This creates $t which is then outputted.


Using only awk, and assuming that the input is a single line only:

awk '{
         for (i = 1; i <= 3; ++i) {
             t = $0;
             sub("HAHA",   i, t)
             sub("HOHO", 4+i, t)
             print t
         }
     }' file

A shell loop for bash, mimicking the awk code above:

read template <file

for (( i = 1; i <= 3; ++i )); do
    t=${template/HAHA/$i}
    t=${t/HOHO/$((i+4))}
    printf '%s\n' "$t"
done
Kusalananda
  • 333,661
  • You said 'Without calling an external utility' - does this mean it runs faster than calling sed? – XYZ Mar 04 '19 at 21:11
  • 1
    @LittleG Calling an external utility, like sed, in a loop is slow in comparison to using only built-in utilities in a loop, yes. – Kusalananda Mar 04 '19 at 21:45