Заменить значение через несколько строк в bash - PullRequest
0 голосов
/ 14 февраля 2020

Я борюсь даже со всеми примерами, доступными в stackoverflow и google.

В основном у меня есть следующий текст

    /start r.start ""
      GAIN 0x256 __POSITIVE 1 FOO
      OTHER
      OTHER
      /start MACRO
        200
        CODE "r.start" 0x256 0x2 10 0xA3
      /end MACRO
      OTHER
    /end

, и мне нужно прочитать этот файл в поисках Назовите egrstart, который передается как $ 1, и подставьте, например, 0x256 значением, которое я передаю как $ 2. Есть два экземпляра для замены, строка 2 и строка 7.

Вещи, которые я знаю:

  1. / начало предшествует 4 пробела
  2. GAIN предшествует 6 пробелы
  3. \ r \ n или \ n могут присутствовать
  4. КОДУ предшествуют 8 пробелов

До сих пор я достиг этой точки

pattern="N;s\s\/start r.start \"\"\n      GAIN 0x\(.*\)"
replacement"\/start r.start \"\"\n      GAIN 0x82"
sed -e "$pattern/$replacement/p" test.txt

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

ожидаемое значение, предполагая, что следующий вызов

./run.sh r.start 0x284569

должен быть

    /start r.start ""
      GAIN 0x284569 __POSITIVE 1 FOO
      OTHER
      OTHER
      /start MACRO
        200
        CODE "r.start" 0x284569 0x2 10 0xA3
      /end MACRO
      OTHER
    /end

Вот мой лучший снимок для второй части

var="r.start"
val="0x48209F82"

pattern="\(CODE \"$var\" \).*\(.*\)"
replacement="\1$val\2"
sed "s/$pattern/$replacement/g" test.txt

Проблема в том, что он удаляет все после подстановки значения. Я не могу вставить \ 2 следующие символы

РЕДАКТИРОВАТЬ:

Делая следующее

var="r.start"
val="0x48209F82"

pattern="\(CODE \"$var\" \).*\(\s.*\s.*\s.*\)"
replacement="\1$val\2"
sed "s/$pattern/$replacement/g" test.txt

Я получаю то, что я хочу, но он немного грязный Как уменьшить последнюю часть в случае переменного числа символов? Могу ли я просто как-нибудь сопоставить все до конца строки?

Ответы [ 4 ]

2 голосов
/ 14 февраля 2020

Как насчет чего-то вроде следующего? Он использует диапазон sed для выбора всего между /start и /end, а внутри диапазона использует блок для замены значения для строк, которые соответствуют GAIN и CODE.

$ cat foo.txt
    /start r.start ""
      GAIN 0x256 __POSITIVE 1 FOO
      OTHER
      OTHER
      /start MACRO
        200
        CODE "r.start" 0x256 0x2 10 0xA3
      /end MACRO
      OTHER
    /end
$ sed '\#/start r\.start#,\#/end#{/\(GAIN\|CODE "r\.start"\)/s/0x[a-fA-F0-9]\+/0x284569/}' foo.txt
    /start r.start ""
      GAIN 0x284569 __POSITIVE 1 FOO
      OTHER
      OTHER
      /start MACRO
        200
        CODE "r.start" 0x284569 0x2 10 0xA3
      /end MACRO
      OTHER
    /end

Сценарий sed выглядит следующим образом при хорошем формате:

\#/start r\.start#,\#/end# {
    /\(GAIN\|CODE "r\.start"\)/s/0x[a-fA-F0-9]\+/0x284569/
}

Примечание

  • использование \#...# вместо /.../ для шаблонов диапазона, поэтому нам не нужно заключать в кавычки
  • использование /patten1/s/pattern2/string/ для замены pattern2 только для строк, содержащих pattern1
  • использование блока {...} для замены применяется только между /start и /end

Вы можете параметризовать шаблон и значение следующим образом:

#!/bin/bash

var='r\.start'
val='0x48209F82'

sed '\#/start '$var'#,\#/end#{/\(GAIN\|CODE "'$var'"\)/s/0x[0-9a-fA-F]\+/'$val'/}' foo.txt
0 голосов
/ 14 февраля 2020

Вот способ perl:

#!/usr/bin/perl 
use strict;
use warnings;

# retrieve the 2 parameters
my $start = shift @ARGV or die "missing 1rst arg";
my $repl =  shift @ARGV or die "missing 2nd arg";

# input file
open my $fh_in, '<', 'file.txt' or die "$!";
# output file
open my $fh_out, '>', 'output' or die "$!";

# loop through input file
while(<$fh_in>) {
    # if we are between /start {1srt parameter} and /end
    if (/^ {4}\/start\h+$start/ ... /^ {4}\/end\h*$/) {
        # substitute 0x.... by {2nd parameter}
        s/^(?: {6}GAIN | {8}CODE "$start" )\K0x\w+/$repl/;
    }
    print $fh_out $_;
}

В действии:

cat file.txt 
    /start other.start ""
      GAIN 0x256 __POSITIVE 1 FOO
      OTHER
      OTHER
      /start MACRO
        200
        CODE "r.start" 0x256 0x2 10 0xA3
      /end MACRO
      OTHER
    /end
    /start r.start ""
      GAIN 0x256 __POSITIVE 1 FOO
      OTHER
      OTHER
      /start MACRO
        200
        CODE "r.start" 0x256 0x2 10 0xA3
      /end MACRO
      OTHER
    /end

./test.pl r.start 0x123456

cat output 
    /start other.start ""
      GAIN 0x256 __POSITIVE 1 FOO
      OTHER
      OTHER
      /start MACRO
        200
        CODE "r.start" 0x256 0x2 10 0xA3
      /end MACRO
      OTHER
    /end
    /start r.start ""
      GAIN 0x123456 __POSITIVE 1 FOO
      OTHER
      OTHER
      /start MACRO
        200
        CODE "r.start" 0x123456 0x2 10 0xA3
      /end MACRO
      OTHER
    /end
0 голосов
/ 14 февраля 2020

Это может работать для вас (GNU sed):

sed -E '/^    \/start r\.start /{:a;N;/^    \/end$/M!ba;s/^(      GAIN |        CODE "r\.start" )0x\S+/\10x284569/Mg}' file

Соберите строки между /start и /end и, используя сопоставление с образцом, замените нужные значения.

Решение может быть помещен в функцию:

f () { sed -E '/^    \/start '"$1"' /{:a;N;/^    \/end$/M!ba;s/^(      GAIN |        CODE "'"$1"'" )0x\S+/\1'"$2"'/Mg}' "$3"; }

И вызван:

f r\\.start 0x284569 file
0 голосов
/ 14 февраля 2020

Для этого вам нужен sed, и вам не нужен скрипт:

Предполагается, что текст представляет собой файл с именем the_text:

sed "s/0x256/REPLACETEXT/g" the_text

Если вы хотите сделать это без вывода эхом из текста затем добавьте -i

sed -i "s/0x256/REPLACETEXT/g" the_text

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

#!/bin/bash

sed "s/0x256/${2}/g" $1
sed "s/0x256/${2}/g" $1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...