3

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
    May 21 at 9:36
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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.