У меня есть несколько файлов pdb, и я хочу сохранить только те строки, которые начинаются с ^FORMUL, и если в строке есть C, а затем число, большее (C3,C4,C5,C6..100 etc), тогда я не должен его печатать. Второе условие состоит в том, что внутри каждой строки сумма C, H and N должна быть не менее 6.
Таким образом, в целом удалите строки, в которых C следует число больше, чем 2> и сумма C+O+N is >= 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, но линии настолько разнообразны друг от друга, поэтому я не уверен, что это возможно.
Хотя он не написан как сценарий оболочки, если кто-то его использует в будущем, вот ответ, как это сделать в 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;
}
Вот мое предложение, к сожалению, у меня нет времени, чтобы написать объяснение прямо сейчас:
$ 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
Хотя он не написан как сценарий оболочки, если кто-то его использует в будущем, вот ответ, как это сделать в 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;
}
Вот мое предложение, к сожалению, у меня нет времени, чтобы написать объяснение прямо сейчас:
$ 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
Хотя он не написан как сценарий оболочки, если кто-то его использует в будущем, вот ответ, как это сделать в 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;
}
Вот мое предложение, к сожалению, у меня нет времени, чтобы написать объяснение прямо сейчас:
$ 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