Usando o awk como mecanismo de template simples, como modificar a saída da última linha do getline

2

Estou tentando usar o awk para fazer alguns modelos simples. Eu tenho um arquivo "modelo" que se parece com isso:

{
  "Thing": {
    "Code": [
      #include_code
    ]
  }
}

Estou usando o programa awk abaixo para substituir a linha #include_code pelo conteúdo de um arquivo, exceto com cada linha envolvida em aspas duplas e terminando a linha com uma vírgula (para criar uma lista JSON válida no meu saída).

#!/usr/bin/awk -f

! /#include_code/ { print $0 }

/#include_code/ {
  while(( getline line<"test_file.js") > 0 ) {
    print "\"" line "\","
  }
}

em que test_file.js é:

index.handler = (event, context) => {
    return true;
}

Meu problema é que não quero imprimir a última vírgula, mas não tenho certeza de como evitar que essa vírgula seja impressa. Para ser explícito, aqui está a saída:

{
  "Thing": {
    "Code": [
"index.handler = (event, context) => {",
"    return true;",
"}", <--- I don't want this comma...
    ]
  }
}

Enquanto eu gostaria de uma resposta que faz isso com o awk (já que estou tentando aprender). Ficarei feliz com uma resposta que me aponte para uma ferramenta diferente para modelos que você recomendaria usar em vez disso.

    
por Thomas Ibbotson 23.08.2017 / 23:33

2 respostas

1

Uma maneira de fazer isso é contar o número de linhas no início do seu script. Ao produzir, emita uma vírgula no final apenas se o número da sua linha não corresponder ao número de linhas. Como fazer isso é explicado aqui .

Outra abordagem é não imprimir uma vírgula ao gerar a primeira entrada e imprimir uma antes das entradas subsequentes. Isso pode ser feito da seguinte maneira:

 awk -F, '{if (!i)printf "\""$0"\"";else printf ",\n\""$0"\"";i=1}END{print ""}' a.in

Isto é definitivamente muito mais limpo.

Existe também uma terceira via. O código

 if(getline == 0)

lê a próxima linha e, portanto, informa se você está no final do arquivo. Fazer isso é ainda mais limpo que o método acima, mas incorre em sobrecarga de ler o arquivo efetivamente duas vezes, então eu não o uso a menos que o segundo método falhe (por exemplo, eu tenho que processar a próxima a última linha de forma diferente também) .

    
por 24.08.2017 / 01:19
0

Pode ser mais fácil fazer isso como:

sed 's/.*/"&"/;$!s/$/,/' test_file.js | sed '/#include_code/{
  r /dev/stdin
  d;}' template

(assumindo que haja apenas uma ocorrência de #include_code ).

Com awk , você poderia fazer como:

awk '
  /#include_code/ {
    sep = ""
    while((getline < "test_file.js") > 0) {
      printf "%s", sep "\"" $0 "\""
      sep = ",\n"
    }
    if (sep) print ""
    next
  }
  {print}' template

Você também pode usar uma abordagem semelhante à sed acima:

CODE='test_file.js' SED='sed '\''s/.*/"&"/;$!s/$/,/'\' "$CODE"' awk '
  /#include_code/{system(ENVIRON["SED"); next};{print}' template
    
por 24.08.2017 / 18:51

Tags