Home > Mobile >  Generate multiple files under subdirectories using a template file and an input file
Generate multiple files under subdirectories using a template file and an input file

Time:10-30

I have an input file input.txt that contains the following values:

# time(t) Temperature Pressure Velocity(u, v, w)
t  T  P   u v w

0       T0 P0 (u0 v0 w0)
0.0015  T1 P1 (u1 v1 w1)
0.0021  T2 P2 (u2 v2 w2)
0.0028  T3 P3 (u3 v3 w3)
0.0031  T4 P4 (u4 v4 w4)
0.0041  T5 P5 (u5 v5 w5)
...    ...  ... ... ...
...    ...  ... ... ...
1.5001  TN PN (uN vN wN)

where Ti, Pi, ui, vi, and wi for i = 0 to N are floating-point numbers.

I have on the other hand, some directories that correspond to the times:

0      # this is a directory
0.0015 # this is a directory also
0.0021 # ...etc.
0.0028
0.0031
...
...

I have a template myTemplate.txt file that looks like the following:

# This is my template file

The time of the simulation is: {%TIME%}

The Temperature is {%T%}
The pressure is {%P%}
The velocity vector is: ({%U%} {%V%} {%W%})

My goal is to create a file output.txt under each time directory using the template file myTemplate.txt and populate the values from the input file input.txt.

I have tried the following:

# assume the name of the directory perfectly matches the time in input file
inputfile="input.txt"
times = $(find . -maxdepth 1 -type d)
for eachTime in $times
do
   line=$(sed -n "/^$eachTime/p" $inputfile)
   T=$(echo "$line" cut -f2 ) # get temperature
   P=$(echo "$line" | cut -f3 ) # get pressure
   U=$(echo "$line" | cut -f4 | tr -d '(') # remove '('
   V=$(echo "$line" | cut -f5 )
   W=$(echo "$line" | cut -f6 | tr -d ')' ) # remove ')'
   
  # I am stuck here, How can I generate a file output.txt from
  # the template and save it under the directory.
done

I am stuck in the step where I need to populate the values in the template file and generate a file output.txt under each directory.

Any help on how to achieve that or may by suggesting an efficient way to accomplish this task using linux standard utilities such as sed, awk is very much appreciated.

CodePudding user response:

I have adapted your bash script which contains multiple typos/errors. This is not the most efficient way to accomplish this but I have tested it on your data and it works:

Create a script file generate.sh:

#!/bin/bash

timedir=$(find * -maxdepth 1 -type d) # use * to get rid of ./ at the beginning
templateFile='./myTemplate.txt' # the path to your template file

for eachTime in $timedir
do

    
    # use bash substitution to replace . with \. in times
    # in order to avoid unexpected matches
    line="$(grep -m 1 -e '^'${eachTime//./\.} input.txt)"

    if [ -z "$line" ]
    then
        echo "***Error***: Data at time: $eachTime were not found!" >&2
        exit 1
    fi
    # the line below is redundant since time is already known
    # replace tabs/and spaces with a single space
    Time=$(echo "$line" | tr -s '[:blank:]' ' ' | cut -d' ' -f1 )
    Temperature=$(echo "$line" | tr -s '[:blank:]' ' ' | cut -d' ' -f2 )
    Pressure=$(echo "$line" | tr -s '[:blank:]' ' ' | cut -d' ' -f3 )
    U=$(echo "$line" | tr -s '[:blank:]' ' ' | tr -d '()' | cut -d' ' -f4 )
    V=$(echo "$line" | tr -s '[:blank:]' ' ' | tr -d '()' | cut -d' ' -f5 )
    W=$(echo "$line" | tr -s '[:blank:]' ' ' | tr -d '()' | cut -d' ' -f6 )

    # Create a temporary file
    buff_file="$(mktemp)"

    # Copy the template to that file
    cp "$templateFile" "$buff_file"

    # Use sed to replace the values
    sed -i "s/{%TIME%\}/$eachTime/g" "$buff_file"
    sed -i "s/{%T%}/$Temperature/g" "$buff_file"
    sed -i "s/{%P%}/$Pressure/g" "$buff_file"
    sed -i "s/{%U%}/$U/g" "$buff_file"
    sed -i "s/{%V%}/$V/g" "$buff_file"
    sed -i "s/{%W%}/$W/g" "$buff_file"

    # Copy that temporary file under the time directory
    cp "$buff_file" "$eachTime"/output.txt
    # delete the temporary file
    rm "$buff_file"

done


echo "Done!"

Run the script:

chmod  x generate.sh
./generate.sh

I have checked that a file output.txt is created under each time directory and contains the correct values from input.txt. The script should also raise an error if a time is not found.

CodePudding user response:

this is a working prototype, note that there is no error handling for missing directories or wrong input formatting etc.

$ awk 'NR==FNR {temp=temp sep $0; sep=ORS;next} 
       FNR==2  {for(i=1;i<=NF;i  ) h[$i]=i} 
       FNR>3   {text=temp; 
                sub("{%TIME%}", $h["t"] ,text); 
                # add other sub(..., text) substitutions!
                print text > ($1 "/output.txt")}' template.txt input.txt

this only replaces the time but you can repeat the same pattern for the other variables.

Reads the template file and saves in variable temp. Reads the input file and captures the header names for easy reference to array h. For each data line, do the replacements and save to the corresponding directory (assumes it exists).

This should be trivial to read:

sub("{%TIME%}", $h["t"], text) substitute {%TIME%} with the value of $h["t"] in variable text.

$h["t"] means the value at index h["t"], which we put the index of t in the header line, which is 1. So instead of writing $1 we can write $h["t"] so the variable we're referring to is documented in place. The other variable you'll refer to again with the names "T", "P", etc.

  • Related