Замена нескольких совпадающих строк с использованием столбцов в файле руководства

Вы можете использовать библиотеку Python. В моей системе Fedora я сделал:

sudo dnf search bcrypt

(sudo предназначен только для того, чтобы не тратить впустую место для пользовательского кеша dnf), и из результата можно увидеть, что есть пакет Python2 и Python3:

py-bcrypt.x86_64 : Python bindings for OpenBSD's Blowfish password hashing code
python3-py-bcrypt.x86_64 : Python 3 bindings for OpenBSD's Blowfish password hashing code

Установите версию Python2 и перечислите файлы в пакете:

sudo dnf install py-bcrypt.x86_64
rpm -ql py-bcrypt.x86_64

Это показывает, что есть файл /usr/lib64/python2.7/site-packages/bcrypt / __ init __. py , поэтому я могу получить документацию с помощью

pydoc bcrypt

Это показывает мне достаточно, чтобы написать следующую команду, которая будет хешировать строку "пароль" :

$ python -c 'import bcrypt; print(bcrypt.hashpw("password", bcrypt.gensalt(log_rounds=10)))'
$2a$10$vWFRZgbOx6RKOKYxCTtyWuMJM60E90Vdm/.0nj.X/o3dYUxvQ/2Dm

Для более поздних версий bcrypt используйте rounds = вместо log_rounds = .

2
10.06.2019, 11:18
4 ответа
$ awk 'FNR==NR { id[$1]=$2; next } { split($1,a,":"); if (a[1] in id) $1=id[a[1]]; print }' fileA fileB
>g01 [PCC6803]
ABCDEFGHIJKLMNOPQRST
>g02 [PCC6803]
UVWXYZABCDEFGHIJKLMN
>g03 [PCC6803]
OPQRSTUVWXYZABCDEFGH

Первый блок будет запущен только при чтении из первого файла(fileA). Он считывает сопоставления строк s*со строками >g*в ассоциативный массив idсо строками s*в качестве ключей.

Второй блок будет запущен только при чтении из второго файла(fileB). Он разделит первое поле каждой строки на :на временный массив a. Если первый элемент результата разделения является ключом в массиве id, все первое поле заменяется значением для этого ключа. Затем печатается возможно измененная строка.

FNR— это номер строки, (на самом деле номер записи, но записи по умолчанию — это строки )текущего файла , а NR— это общий номер строки. Следовательно, если FNR==NRмы читаем из первого файла.

3
27.01.2020, 21:51

Ваша команда sedпочти верна. Вы определили массив с именем replacements, но в цикле forвы используете replacement. Вот почему это не работает. Кроме того, вы хотите заменить всю строку до первого пробела, а не только s/$original/$new/. Этот должен делать то, что вы хотите:

replacements=(
        s12:\>g01
        s16:\>g02
        s48:\>g03
        s52:\>g04
        s80:\>g05
        s81:\>g06
        s87:\>g07
        s91:\>g08
        s92:\>g09
        s93:\>g10
        s94:\>g11
        s96:\>g12
        s97:\>g13
        s98:\>g14
        s99:\>g15
        s100:\>g16
)

for row in "${replacements[@]}"; do
        original="$(echo $row | cut -d: -f1)";
        new="$(echo $row | cut -d: -f2)";
        sed -i -e "s/^${original}:[^ ]*/${new}/g" FileB;
done

Это не очень эффективный способ сделать это, так как вам нужно обрабатывать весь файл B для каждой замены. Более быстрый способ может быть:

$ awk 'NR==FNR{a[$1]=$2; next}{split($1, b, /:/); if(b[1] in a){$1=a[b[1]]}}1;' FileA FileB
>g01 [PCC6803]
ABCDEFGHIJKLMNOPQRST
>g02 [PCC6803]
UVWXYZABCDEFGHIJKLMN
>g03 [PCC6803]
OPQRSTUVWXYZABCDEFGH

И внести изменения для нескольких имен файлов:

awk 'NR==FNR{
        a[$1]=$2; 
        next
     }
     {
        split($1, b, /:/); 
        if(b[1] in a){
            $1=a[b[1]]
        }; 
        print > FILENAME".fixed"
    }' FileA FileB FileC FileD... FileN

Это создаст fileB.fixed, fileC.fixed, fileD.fixedи т. д. до FileN.fixed. Если вы удовлетворены тем, что это сработало, вы можете затем переименовать их обратно в исходное имя файла (, предполагая, что у вас есть переименование perl -, которое используется по умолчанию в Ubuntu и Debian ):

.
rename 's/fixed//' *fixed

Или, если у вас нетperl-rename:

for f in *fixed; do mv -- "$f" "${f%%.fixed}"; done
2
27.01.2020, 21:51

Один метод заключается в использовании sedдля формирования команд s///из содержимого fileAдля выполнения операций с содержимым fileB.

$ sed -Ee 's/(.*) (>.*)/s|^\1:\\S+|\2|;t/' fileA | sed -Ef - fileB

Выход:

>g01 [PCC6803]
ABCDEFGHIJKLMNOPQRST
>g02 [PCC6803]
UVWXYZABCDEFGHIJKLMN
>g03 [PCC6803]
OPQRSTUVWXYZABCDEFGH

Пояснение:

Давайте посмотрим на проблему с обратной стороны, а именно на изменение файла B. Теперь, как будет выглядеть ваша команда sed для редактирования первой строки файла B?

  • что-то в этом роде:s/^s12:\S+/>g01/и тогда вы закончите с этой строкой. поэтому вы помечаете пустую строку t, чтобы сообщить sed, что для этой строки больше не требуется правок.
  • аналогично и для остальных строк.
  • так что теперь мне нужно создать команды sed для просмотра файла A, где вы указали все возможные сопоставления поиска и замены, которые должны быть выполнены.
  • Задача, которая необходима, состоит в том, чтобы каким-то образом преобразовать файл A в допустимые команды sed s///, чтобы при их применении к файлу B мы должны были получить желаемые результаты.
  • эта задача выполняется первой командой sed:s/(.*) (>.*)/s|^\1:\\S+|\2|;t/
  • Первая часть:s/(.*) (>.*)/является левой частью команды замены sed и представляет собой регулярное выражение, в котором мы захватываем и сохраняем два поля в любой заданной строке файла A, например, s12 >g01Итак, \1должен хранить s12и \2должен хранить >g01. Конечно, невысказанным предположением здесь является то, что строки содержат ровно 2 поля с одним пробелом, без начальных пробелов, а 2-е поле начинается с большего -, чем символ >.
  • Таким образом, строка файла A s12 >g01преобразуется в s|^s12:\S+|>g01|;tна основе правой стороны команды sed. эта преобразованная строка затем применяется к файлу B, и мы получаем наши результаты.
  • Для простоты понимания прокомментируйте канал и посмотрите, что генерирует первая команда sed, и все станет ясно. ХТН.
3
27.01.2020, 21:51

Это можно сделать, используя только один вызов GNU sed. Вместо FileB вы можете указать столько файлов, сколько у вас есть в формате FileB, но FileA должен быть указан первым. На всякий случай команда сделает резервную копию входных файлов. Если вас устраивают измененные файлы, после этого вы можете удалить резервные копии.

sed -ri.bk '1{x;s:^:cat /dev/fd/3:e;x};/:/{G;s/^([^:]+)\S+(\s+)([^\n]+).*\1\s+(>[^\n]+).*/\4\2\3/}' 3< FileA FileB

Спасибо @Stéphane Chazelas за то, что он подал мне идею использовать собственный файловый дескриптор, чтобы обойти проблему, связанную с тем, что удерживаемое пространство сбрасывается для каждого нового файла при использовании -i.

0
27.01.2020, 21:51

Теги

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