Jak usunąć wszystkie wiersze spełniające określony warunek

3

Mam kilka plików pdb i chcę zachować tylko te wiersze, które zaczynają się od, ^FORMULa jeśli po wierszu Cwystępuje liczba większa niż (C3,C4,C5,C6..100 etc)wtedy, nie powinienem go drukować. Drugi warunek jest taki, że w każdej linii suma C, H and Npowinna wynosić co najmniej 6.

Więc ogólnie usuń wiersze, po których Cnastępuje liczba, 2>a suma C+O+Nto >=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)

Próbowałem to zrobić, perlale linie są tak różne od siebie, więc nie jestem pewien, czy jest to możliwe.

djordje
źródło
Próbowałem to zrobić w Perlu kilka dni temu, ale chodzi o to, że te linie są tak różnorodne, że musiałbym rozważyć kilka pętli, zrobiłem to (linie podzielone zgodnie z odstępem i nawiasami) i wcisnąłem elementy w tablica, ale to nie ma sensu .. nie mogę tego zrobić (przynajmniej ja). Użyłem tego polecenia w bashu, grep '^FORMUL' *pdb | grep -vE 'C([3-9]|[12][0-9])'ponieważ chciałem usunąć te wiersze, które później Cmają liczbę większą niż 3. Oba warunki powinny zostać uwzględnione, ale nie razem, co oznacza, że ​​jeśli mam C2 N5 02, jest nadal w porządku, chociaż po C następuje1
djordje
Tak więc na przykład C3 N1 01nie należy usuwać, ponieważ ogólnie jest to mniej niż 5, C2 N4 02należy usunąć, chociaż C2istnieją, ogólnie jest to więcej niż 6. Ogólnie usunąć wszystkie wiersze, w których C>2i sum is 6.
djordje
pa4080: Właściwie tak, te warunki muszą zostać połączone. Mój błąd
djordje

Odpowiedzi:

3

Oto moja sugestia, niestety nie mam teraz czasu, aby napisać wyjaśnienie:

$ 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"

Jak tego użyć:

$ 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)

Oto bardzo prosty skrypt, który po prostu wypisuje wiersze do zachowania:

#!/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 < "${@}"

Jak tego użyć:

./script.bash input-file > output-file
pa4080
źródło
Już sam początek odpowiedzi powiedział mi, że to ty, miło! Życzenia na nowy rok ...
George Udosen
Hvala ti Spa, pozdrav is Srbije. Tylko jedno pytanie, kiedy uruchamiam ten skrypt na moich danych, otrzymuję również te, C34 H32 FE N4 O4które są nieco dziwne.
djordje
1
Cześć, @djordje, czy możesz przesłać gdzieś swój plik danych, aby przeprowadzić testy? Поздрави!
pa4080
1
Hej Spa Uczyłem się z tym, pisząc skrypt w perlu. Mogę go przesłać, jeśli chcesz dla własnej satysfakcji, ale myślę, że masz ważniejsze rzeczy do zrobienia: D
djordje
1
@ djordje, nie, nie potrzebowałem tego, jeśli rozwiązałeś problem. Chętnie pomoże!
pa4080
0

Chociaż nie jest napisany jako skrypt powłoki, jeśli ktoś skorzysta z niego w przyszłości, oto odpowiedź, jak to zrobić w Perlu.

#!/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;
}
djordje
źródło
3
Uprzejmie byłoby wspomnieć, że jest to dosłowna odpowiedź @DaveCross opublikowana na Stack Overflow .
PerlDuck,
1
To naprawdę potężne rozwiązanie! Przetwarza plik z dwoma milionami linii przez mniej niż 20 sekund.
pa4080
1
@djordje: Publikowanie kodu innej osoby bez podania jej wiarygodności jest nieco niegrzeczne, prawda?
Dave Cross
1
@djordje: Wkleiłeś wcześniejszą wersję kodu. Naprawiłem błąd w późniejszej edycji.
Dave Cross
2
Tak, zapomniałem powiedzieć, że wszystkie kredyty są przyznawane @Dave Cross. Trochę się spieszyłem, więc naprawdę zapomniałem, chciałem tylko pomóc innym, którzy napotkają podobny problem. Naprawdę nie chciałem dodawać mi kredytów, przepraszam. Jest to bardzo wydajne rozwiązanie w zaledwie kilku liniach kodu. Wielkie dzięki Dave jeszcze raz! Najlepsza!
djordje