GNU sed - Criando uma versão modificada de um modelo existente, com base em um argumento variável

0

Esta questão é sobre renderização de modelos com sed .

Eu tenho o arquivo de modelo nginx_app :

server {
    root ${drt}/${domain}/;
    server_name ${domain} www.${domain};
}

Eu uso esse arquivo em outro script:

#!/bin/bash
domain="$1" && test -z ${domain} && return
sed "s/\${domain}/${1}/g" "nginx_app" > "/etc/nginx/sites-available/${domain}.conf"

O objetivo é ter um example.com.conf como um modelo renderizado, com base em nginx_app , é claro.

Considere este código acima:

sed "s/\${domain}/${1}/g" "nginx_app" > "/etc/nginx/sites-available/${domain}.conf"

Compreendo que este código faz o seguinte:

  1. Altera a string (ainda não expandida) ${domain} pelo argumento de script de ${1} ( example.com ), e isso é feito em algum lugar em RAM , mas sem alterar o arquivo nginx_app em si.
  2. Ele renderiza o modelo nginx_app redirecionando sua versão renderizada para /etc/nginx/sites-available/${domain}.conf .

Assumindo que eu estava correto aqui, devo dizer que essas ações não eram muito intuitivas para mim a partir do código. Eu estava certo na minha descrição desse código?

Por favor, corrija minha descrição se não for suficiente.

    
por user9303970 06.02.2018 / 14:28

3 respostas

2

Sim, sua compreensão na segunda parte do texto está correta.

Pode-se dizer que o

sed , como muitas outras ferramentas do Unix, age como um filtro . Um filtro recebe entrada, modifica e produz saída. Em muitos casos, o utilitário que está fazendo a filtragem pode nem mesmo estar ciente de que está lendo ou gravando um arquivo . Na verdade, ele pode ler ou gravar em outro utilitário de filtro diretamente. Isso é transparente para o próprio utilitário e algo que o shell é responsável pela configuração.

Ignorando o fato de que o seguinte está usando cat desnecessariamente,

cat <file | sed 's/^\([^=]*\)=\(.*\)$/#= # old/' | tr -s ' ' >newfile

Nenhum dos utilitários acima está ciente da leitura de um arquivo ou da gravação em um arquivo. cat lê seu fluxo de entrada padrão (que o shell organiza para conter os dados de file ), provavelmente uma linha por vez, e grava sua saída em seu fluxo de saída padrão (sem modificações).

sed lê o fluxo de entrada padrão its , que o shell já conectou ao fluxo de saída de cat , faz algumas modificações em cada linha de entrada e grava o resultado em sua fluxo de saída padrão (que está conectado a tr ).

tr apenas grava na saída padrão também, mas o shell configura o redirecionamento de tal forma que a saída entre no arquivo newfile .

Em cada etapa deste processo, cada utilitário provavelmente só armazenará o que é minimamente necessário dos dados que passam pelo pipeline (em buffers alocados na RAM). Isso significa que os resultados podem começar a ser gravados em newfile (neste exemplo) antes que os dados no arquivo file tenham sido lidos completamente.

Seu exemplo específico:

sed "s/\${domain}/${1}/g" "nginx_app" > "/etc/nginx/sites-available/${domain}.conf"

O que está acontecendo:

  1. O shell analisa a linha de comando e encontra as variáveis e os redirecionamentos.

  2. O arquivo /etc/nginx/sites-available/${domain}.conf (com $domain expandido para o valor dessa variável) é truncado (ou esvaziado) se existir, ou criado como um arquivo vazio, se não existir.

  3. O utilitário sed é chamado com os operandos s/\${domain}/${1}/g (onde $1 já foi expandido para seu valor, mas ${domain} não, já que o $ é escapado com \ ) e nginx_app . O shell também conecta a saída padrão de sed ao arquivo para o qual você está redirecionando.

  4. Como sed tem dois operandos, ele assumirá que o segundo é um arquivo para leitura. Ele abre e lê linha por linha enquanto aplica os comandos de edição no primeiro operando.

  5. Qualquer saída vai para o arquivo para o qual você redireciona.

Como as pessoas estão mencionando sed -i :

O sinal -i to sed faz com que sed execute suas alterações no arquivo fornecido no lugar , ou seja, ele não gravará em sua saída padrão, mas o resultado de as alterações serão refletidas no mesmo arquivo usado para entrada.

Internamente, sed faz isso gravando em um arquivo temporário que posteriormente substitui o arquivo original.

O -i flag possui um argumento (opcional para o GNU sed e algumas outras implementações do utilitário, obrigatório para outros):

sed -i .bak '...some sed script...' filename

Isso faz o backup do arquivo original com a string fornecida como novo sufixo de nome de arquivo.

Eu geralmente tento desencorajar as pessoas de usar -i com sed , por alguns motivos:

Em vez disso, recomendo que alguém faça algo nas linhas de

sed '...some sed script...' file >file-new && mv file-new file

... e adicione somente a parte && mv quando a parte sed foi testada corretamente.

O && mv significa "se o comando anterior foi finalizado com sucesso (sem erro), renomeie este arquivo".

    
por 06.02.2018 / 14:53
1

Parece que você está perguntando por que você tem que redirecionar a saída para um arquivo, em vez de sed gravar diretamente nesse arquivo. Se assim for, existem algumas razões para isso.

  1. Você pode fazer isso com o argumento -i para sed .
  2. Este não é o comportamento padrão, pois não segue a filosofia comum unix de projetar programas que falam com outros programas ( link ).

    A idéia por trás de muitos utilitários shell unix é que você os encadeia juntos ( foo | bar | baz ). Isso permite que você execute processamento complexo nos dados sem precisar armazená-los em disco no disco entre cada etapa.
por 06.02.2018 / 14:42
1

Sem o sinalizador -i , os resultados de qualquer comando sed serão gravados na saída padrão.

Neste caso, você está redirecionando a saída padrão para outro arquivo ( /etc/nginx/sites-available/${domain}.conf ).

    
por 06.02.2018 / 15:00