簡體   English   中英

在bash中跨多行替換值

[英]Replace value across multiple lines in bash

即使使用 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

我需要通讀這個文件,搜索作為 $1 傳遞的名稱 egrstart 並用我作為 $2 傳遞的值替換例如 0x256。 有兩個實例要替換,第 2 行和第 7 行。

我知道的事情:

  1. /start 前面有 4 個空格
  2. GAIN 前面有 6 個空格
  3. \\r\\n 或 \\n 可能存在
  4. CODE 前面有 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

我得到了我想要的東西,但感覺有點臟,如果字符數可變,我該如何減少最后一部分? 我可以以某種方式匹配所有內容直到行尾嗎?

像下面這樣的怎么樣? 它使用sed范圍來選擇/start/end之間的所有內容,並在該范圍內使用一個塊來替換與GAINCODE匹配的行的值。

$ 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

這可能對你有用(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

這是一個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

您需要為此使用 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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM