Как удалить все строки, которые соответствуют определенному условию

У меня есть несколько файлов pdb, и я хочу сохранить только те строки, которые начинаются с ^FORMUL, и если в строке есть C, за которым следует число, большее, чем (C3,C4,C5,C6..100 etc), я не должен его печатать. Второе условие заключается в том, что в каждой строке сумма C, H and N должна быть не менее 6.

Таким образом, в целом удалите строки, в которых за C следует число, большее, чем 2>, а сумма C+O+N равна >= 6.

FORMUL   3  HOH   *207(H2 O)    (print it)                                     
FORMUL   2  SF4    FE4 S4       (print it)                                                
FORMUL   3  NIC    C5 H7 N O7   (don't print, there is C5)                                               
FORMUL   4  HOH   *321(H2 O)    (print it)                                                
FORMUL   3  HEM    2(C34 H32 FE N4 O4)  (don't print, there is C34)

Я пытался сделать это в perl, но линии так сильно отличаются друг от друга, поэтому я не уверен, возможно ли это сделать.

3
задан 10 January 2018 в 12:07

2 ответа

Вот мое предложение, к сожалению, у меня нет времени, чтобы написать объяснение прямо сейчас:

$ cat script.bash

#!/bin/bash

INPUT_FILE="${1}"
[[ -z "${2}" ]] && OUTPUT_FILE="output-file" || OUTPUT_FILE="${2}"

LINE_COUNTER=1

while read -a line; do

        C_VALUE="$(echo ${line[@]} | grep -Po 'C\d+' | sed 's/C//')"
        O_VALUE="$(echo ${line[@]} | grep -Po 'O\d+' | sed 's/O//')"
        H_VALUE="$(echo ${line[@]} | grep -Po 'H\d+' | sed 's/H//')"
        COH_SUM=$(( C_VALUE + O_VALUE + H_VALUE  ))
        printf '\nLINE=%s: C=%s, O=%s, H=%s, SUM=%s' "$LINE_COUNTER" "$C_VALUE" "$O_VALUE" "$H_VALUE" "$COH_SUM"

        if [[ "$COH_SUM" -ge "6" ]] || [[ "$C_VALUE" -gt "2" ]]; then
                LINES_TO_BE_REMOVED="${LINES_TO_BE_REMOVED};${LINE_COUNTER}d"
        fi

        ((LINE_COUNTER++))

done < "$INPUT_FILE"

printf '\n\nLines to be removed: %s\n\nResult:\n\n' "${LINES_TO_BE_REMOVED#';'}"


sed -e "${LINES_TO_BE_REMOVED#';'}" "$INPUT_FILE" | tee "$OUTPUT_FILE"

Как его использовать:

$ cat input-file
FORMUL   3  HOH   *207(H2 O)
FORMUL   2  SF4    FE4 S4
FORMUL   3  NIC    C5 H7 N O7
FORMUL   4  HOH   *321(H2 O)
FORMUL   3  HEM    2(C34 H32 FE N4 O4)

$ ./script.bash input-file output-file

LINE=1: C=, O=, H=2, SUM=2
LINE=2: C=, O=, H=, SUM=0
...
Lines to be removed: 3d;5d

Result:
FORMUL   3  HOH   *207(H2 O)
...

$ cat output-file
FORMUL   3  HOH   *207(H2 O)
FORMUL   2  SF4    FE4 S4
FORMUL   4  HOH   *321(H2 O)

Здесь это очень простой скрипт, который просто выводит строки, которые нужно сохранить:

#!/bin/bash

while read -a line; do
        C_VALUE="$(echo "${line[@]}" | grep -Po 'C\d+')"
        if [[ ! "${C_VALUE#C}" -gt '2' ]]; then echo "${line[@]}"
        else
                O_VALUE="$(echo "${line[@]}" | grep -Po 'O\d+')"
                H_VALUE="$(echo "${line[@]}" | grep -Po 'H\d+')"
                C_VALUE="${C_VALUE#C}"; O_VALUE="${O_VALUE#O}"; H_VALUE="${H_VALUE#H}"
                if (( (( C_VALUE + O_VALUE + H_VALUE )) <= 6 )); then echo "${line[@]}"; fi
        fi
done < "${@}"

Как его использовать:

./script.bash input-file > output-file
3
ответ дан 10 January 2018 в 12:07

Хотя это не записано как сценарий оболочки, если кто-то использует его в будущем, вот ответ, как сделать это в Perl.

#!/usr/bin/perl


use strict;
use warnings;


#open ($file, '<', '5PCZ.pdb') or die $!; 

while (<>) { # read from STDIN a line at a time
  # Split data on whitespace, but only into three columns
  my @cols = split /\s+/, $_, 3;

  next unless $cols[0] eq 'FORMUL';

  # Now extract the letter stuff into a hash for easy access.
  my %letters = m/([A-Z])(\d+)/g;

  # Give the values we're interested in, a default of 0
  $letters{$_} //= 0 for (qw[C O N]);

  next if $letters{C} > 2
    and $letters{C} + $letters{O} + $letters{N} >= 6;

  # I think we can then print the line;
  print;
}
0
ответ дан 10 January 2018 в 12:07

Другие вопросы по тегам:

Похожие вопросы: