Bashで文字列内のセミコロンをエスケープするにはどうすればいいですか

Bashで文字列内のセミコロンをエスケープするにはどうすればいいですか

現在の DMARC レコードを更新するためのコマンドにフィードするために使用する以下の JSON 文字列を取得しましたaws route53 change-resource-record-sets。ご覧のとおり、TXT 値にはが含まれています;

JSON="{ \"Comment\": \"Updating TXT record in $domain\", 
  \"Changes\": [ { \"Action\": \"UPSERT\", \"ResourceRecordSet\": { \"Name\": 
  \"_dmarc.${domainName}\", \"Type\": \"TXT\", \"TTL\": 
  3600, \"ResourceRecords\": [ { \"Value\": "\"v=DMARC1\; p=reject\; pct=100\"" } ] } } ] }"

を実行するとecho $JSON、JSON 文字列全体ではなく、以下の出力が得られました。 に到達するとすぐに解析が停止するようです;

{ "Comment": "Updating TXT record in ", 
  "Changes": [ { "Action": "UPSERT", "ResourceRecordSet": { "Name": 
  "_dmarc.contoso.com", "Type": "TXT", "TTL": 
  3600, "ResourceRecords": [ { "Value": "v=DMARC1;

\\;およびを使用するなど、セミコロンをエスケープする方法をいくつか試しましたが、\";\"うまくいきませんでした。ここで何を間違えたのでしょうか?

答え1

一重引用符と二重引用符を混ぜて使用すると、見た目が乱雑にならず、作業もしやすくなります。

JSON='{ "Comment": "Updating TXT record in $domain", 
  "Changes": [ { "Action": "UPSERT", "ResourceRecordSet": { "Name": 
  "_dmarc.${domainName}", "Type": "TXT", "TTL":  
  3600, "ResourceRecords": [ { "Value": "v=DMARC1; p=reject; pct=100" } ] } } ] }'

これは機能します。例:

$ JSON='{ "Comment": "Updating TXT record in $domain",
  "Changes": [ { "Action": "UPSERT", "ResourceRecordSet": { "Name":
  "_dmarc.${domainName}", "Type": "TXT", "TTL":
  3600, "ResourceRecords": [ { "Value": "v=DMARC1; p=reject; pct=100" } ] } } ] }'
$
$ echo $JSON | jq .
{
  "Comment": "Updating TXT record in $domain",
  "Changes": [
    {
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "_dmarc.${domainName}",
        "Type": "TXT",
        "TTL": 3600,
        "ResourceRecords": [
          {
            "Value": "v=DMARC1; p=reject; pct=100"
          }
        ]
      }
    }
  ]
}
$

答え2

ここでの問題はセミコロンのエスケープではなく、セミコロンの後のスペースであることがわかりました。文字列を次のように変更した後、

{ \"Value\": "\"v=DMARC1\;\ p=reject\;\ pct=100\"" }

文字列が適切にエコーされるようになりました。

{ "Value": "v=DMARC1; p=reject; pct=100" }

答え3

末尾のいくつかの引用符とバックスラッシュにエスケープがありません。JSON ドキュメント文字列を一重引用符で囲むと、引用符の管理が簡単になります。

シェル変数の値を JSON ドキュメントに挿入したいようです。これを最も安全に行うには、次の方法を使用しますjq

$ domain=my.domain.example.com
$ domainName=some-domain-name
$ JSON=$( jq -c -n --arg domain "$domain" --arg name "$domainName" '
{ "Comment": "Updating TXT record in \($domain)",
  "Changes": [ {
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "_dmarc.\($name)", "Type": "TXT", "TTL": 3600,
        "ResourceRecords": [ { "Value": "\"v=DMARC1; p=reject; pct=100\"" } ]
      } } ] }' )

ここで、コマンドは 2 つのシェル変数とjqの値をインライン JSON ドキュメントに挿入するために使用されます。 2 つの変数は、それぞれ 2 つの内部変数とを初期化するためにコマンド ラインで使用されます。 これらは、挿入されるはずの文字列内で JSON ドキュメントによって参照されます。domaindomainNamejq$domain$name

この方法により、特別なエスケープが必要な文字が適切にエスケープされ、ドキュメント内の JSON 文字列に含まれるようになります。

文字列の最後に埋め込まれた二重引用符は、必須かどうかわからないため、そのまま残してあることに注意してください。JSON パーサーは、データを読み取るときにエスケープされた引用符を適切にデコードします。

関連情報