1

I have a text file in the following format:

Model        1   
Atom….
Atom….
Atom….
ENDMDL
Model        2   
Atom….
Atom….
Atom….
ENDMDL
Model       n   
Atom….
Atom….
Atom….
ENDMDL

I need to split this file into the files corresponding to each Model. The names of new files according to the Model’s number.

3 Answers3

4

This is easily done using a small awk script.

#!/usr/bin/awk -f 
# Write sections of the input file to separate files
# Written by PM 2Ring 2016.06.14

BEGIN{outbase = "outfile"}

/^Model/{outname = outbase $2}

{print > outname}

outbase is the base file name. It gets the Model number appended to it, so for your sample file the output files outfile1, outfile2, etc will get created. With a minor change to the script you could set outbase from the command line, using awk's -v option.

The heart of this script is

/^Model/{outname = outbase $2}

It says: If the current line starts with "Model" append the contents of field #2 to the outbase string, assigning the result to outname.

By default, awk process a file line by line, splitting each line into fields using whitespace as the field separator.

{print > outname}

simply prints the current line to the file whose name is stored in outname.


This script is small enough to write the whole thing on the command line:

awk 'BEGIN{outbase = "outfile"}; /^Model/{outname = outbase $2}; {print > outname}' infile.txt

You can actually supply multiple input file arguments and they will be handled correctly, as long as you don't have duplicated Model numbers.

PM 2Ring
  • 6,633
1

I would probably go for this using csplit. This will work for a file called file.txt:

csplit -ksz file.txt '/^Model/' '{*}'
for xx in xx*
do
    newname=$(awk '{print $2; exit}' "$xx")
    test ! -f "$newname" && mv -f "$xx" "$newname"
done

The csplit splits file.txt into multiple parts based on the RE. Filenames are (by default) named as xx and a monotonically increasing numeric suffix. We look at each of these in turn and rename them to the model number found inside the file.

Any files matching xx* at the end of the loop contain duplicate model numbers (the renaming is performed on a first come first served basis).

Chris Davies
  • 116,213
  • 16
  • 160
  • 287
0
#!/bin/bash                                                                                                                                                                                                                                   

while read -r line                                                                                                                                                                                                                            
do                                                                                                                                                                                                                                            
    case $line in                                                                                                                                                                                                                             
        Model*)                                                                                                                                                                                                                               
            f="${line//[[:space:]]/}"
            touch "$f"  # file name without white spces                                                                                                                                                                                                                     
            ;;                                                                                                                                                                                                                                
        ENDMDL)                                                                                                                                                                                                                               
            :                                                                                                                                                                                                                                 
            ;;                                                                                                                                                                                                                                
        *)                                                                                                                                                                                                                                    
            echo "$line" >> "$f"                                                                                                                                                                                                              
            ;;                                                                                                                                                                                                                                
    esac                                                                                                                                                                                                                                      
done < "$1"

Something like this. You should run it providing models file as argument: ./script_name models.txt

Note that as mentioned by @PM 2Ring this approach is slow specially if you have large files.

Vombat
  • 12,884