Como inserir texto após a última linha de configuração?

5

Eu tenho que inserir uma linha em um arquivo de configuração automaticamente, mas com a ressalva adicional de que ele deve ser inserido antes um comentário de rodapé de várias linhas e qualquer linha anterior vazia ou em branco apenas se o rodapé existir . Ou seja, a nova linha deve ser inserida logo após a última linha de configuração , criando um diff de linha única a partir do arquivo original. No pseudo-código:

  1. Ir para o final do arquivo.
  2. Retroceda para a primeira linha de configuração (isto é, a última no arquivo) (ou seja, uma linha que não seja vazia, somente espaço em branco, apenas comentário ou espaço em branco seguido por um comentário).
  3. Inserir texto após a linha atual.

Expressão regular estendida para a linha de configuração: ^\s*[^[:space:]#]

Todas as ferramentas comuns * nix, como sed , awk , ed ou ex , devem funcionar.

Possíveis soluções e seus problemas:

  • Use tac duas vezes para transformar isso em um problema de pesquisa avançada em vez de pesquisa inversa. Isso significa que terei que armazenar o resultado em um arquivo temporário e substituir o original, em vez de fazer isso em um único comando.
  • Use sed -i com o reversão truque. Isso significa armazenar todo o arquivo na memória.
  • ex -c '1' -c '?^\s*[^[:space:]#]?' -c $'a\nmy new line\n.' -c 'wq' /path , que também estou informado de que armazena o arquivo completo na memória.

Existe uma solução que contorne essas duas questões?

Exemplo de arquivo inicial:

# Universe configuration
#

pi = 3 # A good #
e = mc**2 # To within a hair

[cut 200 trillion lines]

# 
# END
#

Exemplo de entrada:

sol { mass = 42, start = 9.2 }

Resultado esperado:

# Universe configuration
#

pi = 3 # A good #
e = mc**2 # To within a hair

[cut 200 trillion lines]
sol { mass = 42, start = 9.2 }

# 
# END
#

Função de propósito geral baseada em @ A solução de StephaneChazelas

    
por l0b0 07.06.2013 / 11:13

3 respostas

2

Você poderia fazer algo ao longo destas linhas:

file=/some/file
newtext='sol { mass = 42, start = 9.2 }'
tac -- "$file" | 
  NEWTEXT=$newtext awk -v size="$(wc -c < "$file")" '
    $1 ~ /^[^#]/ {
      system("dd bs=1 seek=" size - length(footer) " conv=notrunc if=/dev/null")
      printf "%s\n%s", ENVIRON["NEWTEXT"], footer
      exit
    }
    {footer=$0 "\n" footer}' 1<> "$file"

Isso substitui o arquivo no lugar e armazena apenas o rodapé na memória. Ele precisa do comando não padrão GNU tac . O arquivo tem que ser um arquivo de texto normal.

    
por 07.06.2013 / 14:02
0
Solução somente

awk (testada com o gawk):

$ awk '
    BEGIN   {   footer = ""; wl = ""; } 
    END     {   while(( getline line < "sol.txt") > 0 ) {
                    print(line)
                }
                footer = wl footer
                print substr(footer, 0, length(footer)-1); 
            }

    # Blank line
    /^[[:blank:]]*$/ {
                if (footer) {
                    footer = wl footer
                    print substr(footer, 0, length(footer)-1); 
                    footer = ""
                }
                wl = $0 "\n"
            }
    # Comment only
    /^[[:blank:]]*#/ {
                footer = footer $0 "\n"; 
            }

    # Configuration line
    /^[[:blank:]]*[^[:space:]#]/ {
                print(wl footer $0); wl = ""; footer = ""; 
            }
    ' <  universe.txt > universe2.txt

Produção:

# Universe configuration
#

pi = 3 # A good #
e = mc**2 # To within a hair

[cut 200 trillion lines]
sol { mass = 42, start = 9.2 }

# 
# END
# 

Com um diff de linha:

sh$ diff universe*.txt
8d7
< sol { mass = 42, start = 9.2 }
    
por 07.06.2013 / 18:44
-1

Este é um arquivo de configuração, por isso cabe confortavelmente na memória. Não há necessidade de processá-lo como um fluxo.

newline='
' tab=$(echo | tr '\n' '\t')
old=$(cat foo.config)
footer=${old##*"$newline[!$newline$tab #]"}
if [ "$footer" = "$old" ]; then
  footer=
else
  footer=${footer#*"$newline"}
fi
head=${old%"$footer"}
echo "$head$text_to_insert$footer" >foo.config.new
    
por 11.06.2013 / 02:45