Home > database >  How to replace one specific line of many files from one instruction file in batches?
How to replace one specific line of many files from one instruction file in batches?

Time:08-01

We hope to replace the Line 3 of file001 to file600 with corresponding line in the instruction.txt, and is there any possible solution in bash language? I thought maybe I could write a script with sed or awk command, but I couldn't come up with it. Any help would be appreciated. Thanks!

The file001 to file600 contain many cartesian coordinates and are of the same format. E.g. file001 is as follows:

3.02  5.46  8.94
4.55  3.22  4.35
0.00  0.00  0.00 # this is the wrong line and we want to get it replaced
2.34  3.32  5.47
...

The instruction.txt file is:

file001
3.25  1.13  6.10  #this means to replace the 3rd line of "file001" with "3.25  1.13  6.10"
file002
6.01  1.17  -0.32  #this means to replace the 3rd line of "file002" with "6.01  1.17  -0.32"
...

CodePudding user response:

My solution look pretty messed up, but it works :) you can try it, let me know if it works for you.

for i in `cat instruction.txt | awk 'NR % 2 == 1 { printf $0; printf "\n" }'`; do
        outp=`awk '/'"$i"'/{getline; print}' instruction.txt`;
        sed -i '3s/0.00  0.00  0.00/'"$outp"'/' $i;
done

First, I try to filter all the odd lines that contain filename, and assign it to the variable $i:

cat instruction.txt | awk 'NR % 2 == 1 { printf $0; printf "\n" }'

Then get the next line of every $i, which is fix value and assign it to the variable $outp:

outp=`awk '/'"$i"'/{getline; print}' instruction.txt`

And finally, replace the wrong 3rd line with 2 variables I just received.

sed -i '3s/0.00  0.00  0.00/'"$outp"'/' $i

CodePudding user response:

Here would be a solution with GNU awk >= 4.1.0 (I didn't test the inplace part because I don't have the correct version at hand):

awk -i inplace '
    BEGIN {
        while ( (getline filename < ARGV[1] > 0) && (getline data < ARGV[1] > 0) )
            instructions[filename] = data
        close(ARGV[1])
        delete ARGV[1]
    }
    FNR == 1 {
        filename = FILENAME
        sub(/.*\//,"",filename)
    }
    FNR == 3 && filename in instructions {
        print instructions[filename]
        next
    }
    1
' instructions.txt file[0-9][0-9][0-9]

The code first first loads instructions.txt then modifies the 3rd line of the other files if their "basename" is found in the instructions

CodePudding user response:

while read -r line; do 
  if [[ $(sed -E 's/^([^ ]*).*/\1/' <<< "$line") =~ "file" ]]; then 
    file=$line
  elif [[ $(sed -E 's/^([^ ]*).*/\1/' <<< "$line") =~ [0-9.] ]]; then 
    sed -i.bak "3c$line" "$file"
  fi
done < instructions.txt
  •  Tags:  
  • bash
  • Related