awkを単純なテンプレートエンジンとして使用して、getlineの最後の行出力を変更する方法

awkを単純なテンプレートエンジンとして使用して、getlineの最後の行出力を変更する方法

私はawkを使っていくつかの簡単なテンプレートを作成しようとしています。次の「テンプレート」ファイルがあります。

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

次のawkプログラムを使用して#include_code行をファイルの内容に置き換えましたが、各行を二重引用符で囲んでカンマで終わりました(出力に有効なJSONリストを生成するため)。

#!/usr/bin/awk -f

! /#include_code/ { print $0 }

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

どこtest_file.js

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

私の問題は、最後のカンマを印刷したくないのですが、そのカンマが印刷されるのを防ぐ方法がわかりません。明確に言えば、次のような結果が出ます。

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

awkを使ってこれを行うことに答えたいのですが(学びたいので)。あなたが私にそれを使うように提案した他のテンプレートツールを教えてくれる答えがあります。

答え1

1つの方法は、スクリプトの先頭の行数を数えることです。出力時に行番号と行数が一致しない場合にのみ、最後にコンマを出力してください。これを行う方法を説明します。ここ

別の方法は、最初の項目を出力するときにカンマを印刷する代わりに今後以降の項目。これは次のように実行できます。

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

確かにはるかにきれいになりましたね。

3番目の方法があります。パスワード

 if(getline == 0)

ファイルの最後にあるかどうかを示す次の行を読みます。これは上記の方法よりもきれいですが、ファイルを効果的に2回読み取るオーバーヘッドが発生するため、2番目の方法が失敗しない限り、この方法は使用しません(たとえば、最後の2番目の方法も別の方法で処理する必要があります。OK) 。

答え2

これを行う方が簡単かもしれません。

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

(一度だけ現れると仮定#include_code)。

を使用すると、awk次のことができます。

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

sed上記と同様のアプローチを使用することもできます。

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

関連情報