4

I have a file on Linux, containing the coordinates of thousands of molecules. Each molecule starts with a line containing always the same pattern:

@<TRIPOS>MOLECULE

And then continues with other lines. I would like to split the file into multiple files, each containing a certain number of molecules. What is the easiest way to do this?

1
  • 2
    How many molecules per file? How should the files be named? Can you give us a more complete example of the file? Does the line "contain" the @<TRIPOS>MOLECULE, so it could occur anywhere in the line, or is the line only @<TRIPOS>MOLECULE? Or perhaps it starts with @<TRIPOS>MOLECULE? Can the pattern occur anywhere else?
    – terdon
    Commented May 21, 2021 at 9:36

2 Answers 2

10

One way is to use awk:

awk -v moleculesNum=7 '
/^@<TRIPOS>MOLECULE/{
    if((++num)%moleculesNum==1){
        close(outfile); outfile="file" (++Output)
    }
}
{ print >outfile }' infile

this splits the original file into multiple files each having maximum 7 number of MOLECULEs (adjustable in moleculesNum=7 parameter)

0
2

The following is a bash-based csplit utility approach:

### user customization section
tmpdir=$(mktemp -d)
prefix='outfile'
bunch=5
pat='@<TRIPOS>MOLECULE'

## break up the input file on pattern
csplit ./file \
  --silent \
  --elide-empty-files \
  --prefix "$tmpdir/$prefix" \
  --suffix-format='%d.tmp' \
  "/$pat/+1" '{*}' \
;

## coalesce the split up files into bunches
i=0
while :; do
  start=$(( bunch * i ))
  stop=$(( start + bunch - 1 ))
  for ((j=start; j<=stop; j++)) {
    printf '%s\n' "$tmpdir/$prefix$j.tmp"
  } | xargs cat > "./$prefix.$i" 2>/dev/null || break
  (( i++ ))
done

The current directory will hold the outfiles.* bunches.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .