Замена определенного столбца SED

Я согласен с использование find является лучшим вариантом . Но я хочу добавить, почему ваша команда не работает.

Ваша команда:

$ ls process_logs/ | grep -P '^some_pattern_matching_regex_goeshere.txt$' | xargs rm -f

lsвыводит имена файлов без пути . Но вы не добавляете путь к rm. Таким образом, он попытается удалить имена файлов из вашего подкаталога в вашем текущем/корневом каталоге.

Попробуйте

$ cd process_logs/; ls | grep -P '^some_pattern_matching_regex_goeshere.txt$' | xargs rm -f

Или

$ ls process_logs/ | grep -P '^some_pattern_matching_regex_goeshere.txt$' | xargs -i rm -f "process_logs/{}"
0
14.02.2020, 22:12
4 ответа

Поскольку интервал должен оставаться фиксированным, возможно, это означает, что весь макет фиксирован, и тогда это может быть то, что вы ищете, используя sed, который поддерживает -E, чтобы включить ERE, такие как GNU sed или OSX/BSD. сед:

$ sed -E 's/(.{17})A /\1RA/' file
ATOM     32  P     RA    2       6.882  -5.338   6.560  1.00  0.00           P
ATOM     33  OP1   RA    2       7.505  -5.970   7.750  1.00  0.00           O
ATOM     34  OP2   RA    2       5.404  -5.201   6.610  1.00  0.00           O
TER

или с любым POSIX-кодом:

$ sed 's/\(.\{17\}\)A /\1RA/' file
ATOM     32  P     RA    2       6.882  -5.338   6.560  1.00  0.00           P
ATOM     33  OP1   RA    2       7.505  -5.970   7.750  1.00  0.00           O
ATOM     34  OP2   RA    2       5.404  -5.201   6.610  1.00  0.00           O
TER

РЕДАКТИРОВАТЬ :ваш ввод, похоже, не соответствует стандарту pdb , который @bushman опубликовал ранее, но если это так, вот как вы можете использовать информацию из стандарта для создания массива f[]полей по их тегам/именам, изменять их по их тегу/имени (в отличие от их относительного положения во вводе )и печатать их в том же формате с фиксированной шириной:

$ cat tst.awk
BEGIN {
    # Record Format (copied from http://www.wwpdb.org/documentation/file-format-content/format33/sect9.html#ATOM)
    #
    #                 COLUMNS        DATA  TYPE    FIELD        DEFINITION
    #                 -------------------------------------------------------------------------------------
    flds[++numFlds]="  1 -  6        Record name   ATOM  "
    flds[++numFlds]="  7 - 11        Integer       serial       Atom  serial number."
    flds[++numFlds]=" 13 - 16        Atom          name         Atom name."
    flds[++numFlds]=" 17             Character     altLoc       Alternate location indicator."
    flds[++numFlds]=" 18 - 20        Residue name  resName      Residue name."
    flds[++numFlds]=" 22             Character     chainID      Chain identifier."
    flds[++numFlds]=" 23 - 26        Integer       resSeq       Residue sequence number."
    flds[++numFlds]=" 27             AChar         iCode        Code for insertion of residues."
    flds[++numFlds]=" 31 - 38        Real(8.3)     x            Orthogonal coordinates for X in Angstroms."
    flds[++numFlds]=" 39 - 46        Real(8.3)     y            Orthogonal coordinates for Y in Angstroms."
    flds[++numFlds]=" 47 - 54        Real(8.3)     z            Orthogonal coordinates for Z in Angstroms."
    flds[++numFlds]=" 55 - 60        Real(6.2)     occupancy    Occupancy."
    flds[++numFlds]=" 61 - 66        Real(6.2)     tempFactor   Temperature  factor."
    flds[++numFlds]=" 77 - 78        LString(2)    element      Element symbol, right-justified."
    flds[++numFlds]=" 79 - 80        LString(2)    charge       Charge  on the atom."

    for (fldNr=1; fldNr<=numFlds; fldNr++) {
        fld = flds[fldNr]

        cols = substr(fld,1,16)
        gsub(/ /,"",cols)
        n = split(cols,begEnd,/-/)

        tag  = substr(fld,31,13)
        gsub(/ /,"",tag)

        tags[fldNr] = tag
        begs[tag] = begEnd[1]
        wids[tag] = begEnd[n] - begEnd[1] + 1

        # Uncomment this if interested in the values the arrays contain:
        # print "<" fldNr "><" tags[fldNr] "><" begs[tag] "><" wids[tag] ">" | "cat>&2"
    }
}

{
    for (fldNr=1; fldNr<=numFlds; fldNr++) {
        tag = tags[fldNr]
        f[tag] = substr($0,begs[tag],wids[tag])
        gsub(/^ +| +$/,"",f[tag])
    }
}

f["resName"] == "A" { f["resName"] = "RA" }     # this is where you can change a field by its tag/name

{
    for (fldNr=1; fldNr<=numFlds; fldNr++) {
        tag = tags[fldNr]
        printf "%-*s", wids[tag], f[tag]
    }
    print ""
}
$
$ awk -f tst.awk file
ATOM  32   P    RA  2    6.882   -5.338  6.560   1.00  0.00  P
ATOM  33   OP1  RA  2    7.505   -5.970  7.750   1.00  0.00  O
ATOM  34   OP2  RA  2    5.404   -5.201  6.610   1.00  0.00  O
TER

Очевидно, что это излишне для того, что вы пытаетесь сделать прямо сейчас, но это хороший общий подход, о котором следует помнить, и он решает проблему, с которой вы можете столкнуться при любом другом подходе, обсуждаемом до сих пор, с пустыми полями перед интересующим вас полем. дюйм

1
28.04.2021, 23:23

Если вы просто хотите получить красивый печатный табличный вывод с заменой столбцов, следующее дополнение к вашей команде awkпозволит добиться этого:

awk ' gsub("A","RA",$4){for (i=1;i<=NF;i++){printf("%-9s",$i)}print "" }' a.txt > b.txt

с выводом cat b.txt, который выглядит как:

ATOM     32       P        RA       2        6.882    -5.338   6.560    1.00     0.00     P
ATOM     33       OP1      RA       2        7.505    -5.970   7.750    1.00     0.00     O
ATOM     34       OP2      RA       2        5.404    -5.201   6.610    1.00     0.00     O

Если вы ищете более конкретное расстояние между каждым столбцом, вам придется отказаться от цикла printfи назначить индивидуальное расстояние для каждого поля.


Если вы ищете очень быструю sedальтернативу, вы всегда можете просто:

sed 's/ A /RA/' a.txt > b.txt

, но это заменит каждый «A» в файле на «RA», не ограничиваясь 4-м столбцом, поскольку sedиспользует другой метод разделения полей, чем awk. Тем не менее, использование приведенной выше команды sedдаст вам cat b.txt, который будет выглядеть следующим образом:

ATOM     32  P    RA    2       6.882  -5.338   6.560  1.00  0.00           P
ATOM     33  OP1  RA    2       7.505  -5.970   7.750  1.00  0.00           O
ATOM     34  OP2  RA    2       5.404  -5.201   6.610  1.00  0.00           O
0
28.04.2021, 23:23

Использованиеsed

sed -E "s/^(([^ ]+ +){3})A  /\1RA /" file1

Прохождение

С начала строки ввода^

([^ ] +)означает захватить группу ( )как непрерывную последовательность не -пробелов [^ ]+, за которой следует еще одна непрерывная последовательность пробелов+

Захватите эту группу для {3}повторений, чтобы следующие символы были в вашем четвертом поле

Сгруппируйте все три повторения вместе, обернув( )

Если за этой «супергруппой», которая сейчас хранится в \1, следует A(, то есть A с 2 пробелами ), замените ее на \1RA(, только с 1 завершающим пробелом, чтобы вы сохранили символ считать одинаково)

0
28.04.2021, 23:23

Метод -1 :GNU sed без обратных ссылок

$ sed -re '
     h
     s/\S+/\n&\n/4
     s/\nA\n/RA/;t
     g
 ' file

Метод -2 :GNU sed с обратными ссылками.

 $ sed -re '
      s/^(\s*(\S+\s+){3})(A(\s|$))/\1R\3/
 ' file

Обратите внимание, что оба решения sed можно сделать совместимыми с Posix, но это будет стоить чистоты кода и может привести к обратной косой черте.

Метод -3 :Perl использует awk-подобные поля, НО с изюминкой, этот хранит как значения полей, так и разделители. Таким образом, 4-е поле становится 8-м, а с массивом с нулевым индексом оно равно 7.

$ perl -F'/(\S+)/' -lane '
     $F[7] =~ s/^A$/RA/;
     print @F;\
 ' file 
0
28.04.2021, 23:23

Теги

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