bash / sh script para substituir o texto entre algumas tags / strings em um arquivo de texto

2

Estou criando um executável que será executado com o script / bin / sh ou / bin / bash,
Eu tenho um arquivo que contém uma estrutura como, haverá apenas uma tag #start e #end no arquivo de configuração, e eu quero substituir o texto entre essas tags,

...

#start
FirewallRuleSet global {
    FirewallRule allow tcp to google.com
    FirewallRule allow tcp to facebook.com

#more rules
}
#end

FirewallRuleSet known-users {
    FirewallRule allow to 0.0.0.0/0
}

...

A saída desejada será

...

#start
FirewallRuleSet global {
    FirewallRule allow tcp to google.com
    FirewallRule deny tcp to facebook.com
    FirewallRule deny tcp to twitter.com
    FirewallRule allow tcp to exaple.com



#more rules
}
#end

FirewallRuleSet known-users {
    FirewallRule allow to 0.0.0.0/0
}

...

Como posso substituir todo o texto entre #start e #end com algum novo texto? Eu só quero adicionar ou remover regras deste arquivo de configuração.

Isso faz parte de um arquivo de configuração e eu quero modificar o URL permitido dentro desses textos.

    
por Straw Hat 25.03.2016 / 07:56

3 respostas

3

Use

sed '/#start/,/#end/replace_command'

Por exemplo, se o arquivo for chamado myconfig , e você quer substituir "allow" por "deny" nessa seção, você poderia dizer

sed '/#start/,/#end/s/allow/deny/' myconfig

Isso deixaria o arquivo intacto e exibido na saída padrão como ficaria o arquivo após a modificação. Você provavelmente deveria fazer isso primeiro, para verificar se você tem o comando certo. Se você quiser realmente alterar o arquivo, adicione a opção -i :

sed -i '/#start/,/#end/s/allow/deny/' myconfig

Se você quiser substituir o texto todo ( todos o texto) entre essas duas linhas, você pode fazer algo um pouco mais simples do que de Lucas resposta :

sed '/#start/,/#end/c\
New text line 1\
New text line 2\
        ︙      \
New text line n-1\
New text line n (last)'                                   ← Close quote; no backslash here

c é o c comando hange em sed (% eed); significa "substituir linhas inteiras". Você não pode simplesmente deixar as linhas #start e #end intocadas. Se você quiser mantê-los, você deve reinseri-los:

sed -i '/#start/,/#end/c\
#start\
FirewallRuleSet global {\
    FirewallRule allow tcp to google.com\
    FirewallRule deny tcp to facebook.com\
                      ︙                 \
\
#more rules\
}\
#end' myconfig

/#start/,/#end/ especifica um intervalo - as linhas da primeira linha que contém #start através da primeira linha depois que contém #end . Se você precisar encontrar linhas que contenham essas cadeias de caracteres e nada mais, use /^#start$/,/^#end$/ .

    
por 25.03.2016 / 08:22
3

Com base na resposta do G-Man e no comentário:

sed -i '/#start/,/#end/ {
//!d
/#start/a\
some new text\
more lines\
end of new text (no backslash here!)
}' myconfig

Explicação:

  1. /#start/,/#end/ { .... } executa os comandos entre chaves para cada linha entre o texto "#start" e "#end" (inclusive). Compare a resposta do G-Man.
  2. a é o comando append. Só é executado na linha correspondente "#start" para adicionar o novo texto. Ele anexa as linhas até uma linha que não é terminada com uma barra invertida + nova linha.
por 25.03.2016 / 10:42
0

Como você tem dois estados, a presença de duas linhas diferentes é uma tarefa para awk (ou perl ou python). Como meu idioma atual é python, o programa ficaria assim:

import sys

rule_file = sys.argv[1]
new_rules = sys.argv[2]

mode = "save_rules"
for line in open(rule_file):
    line = line.strip()
    if line == "#start":
        print line
        print new_rules
        mode = "replace_rules"
    elif line == "#end":
        mode = "save_rules"
        print line
    elif mode == "save_rules":
        print line

Agora salve isso em rule_replace.py e chame-o com

python rule_replace.py my_rule_file.txt 'FirewallRuleSet global {
FirewallRule allow tcp to google.com
FirewallRule deny tcp to facebook.com
FirewallRule deny tcp to twitter.com
FirewallRule allow tcp to exaple.com



#more rules
}' >new_rules.txt

Claro que você não tem que colocar as novas regras na linha de comando, eu estou supondo que você as teria em uma variável de shell e, em seguida, a chamada seria semelhante:

$ python rule_replace.py my_rule_file.txt $new_rules

Observe que esse script, embora funcione, não é uma solução para algo em produção. Ele não captura nenhum erro (por exemplo, se o arquivo de origem não estiver lá). Assume-se sem verificar que uma linha #start é sempre seguida por uma linha #end e que as linhas são exatamente como você descreveu. Ele também pode usar alguns registros se estiver em produção.

    
por 25.03.2016 / 17:47