web-dev-qa-db-ja.com

複雑な複数行の文字列を変数に書き込むクリーンな方法

Bashスクリプト内の変数に複雑なxmlを書き込む必要があります。これはxmlフラグメントが存在する場所であり、別のファイルまたはソースから読み取られていないため、bashスクリプト内でxmlが読み取り可能である必要があります。

ですから、私の質問は、bashスクリプト内で人間が読めるようにしたい長い文字列がある場合、これについてどのように対処するのが最善ですか?

理想的には:

  • どの文字もエスケープする必要がない
  • 人間が読めるようにするために複数の行にまたがる
  • インデントのままにします

EOFまたは何かでこれを行うことができますか、誰か私に例を挙げてもらえますか?

例えば.

String = <<EOF
 <?xml version="1.0" encoding='UTF-8'?>
 <painting>
   <img src="madonna.jpg" alt='Foligno Madonna, by Raphael'/>
   <caption>This is Raphael's "Foligno" Madonna, painted in
   <date>1511</date>-<date>1512</date>.</caption>
 </painting>
EOF
112
ChrisInCambo

これにより、引用符をエスケープする必要なく、テキストが変数に入れられます。また、不均衡な引用符(アポストロフィ、つまり')。センチネル(EOF)を引用符で囲むと、テキストがパラメーター展開されなくなります。 -d''を指定すると、複数行が読み取られます(改行は無視されます)。 readはBashの組み込みなので、catなどの外部コマンドを呼び出す必要はありません。

IFS='' read -r -d '' String <<"EOF"
<?xml version="1.0" encoding='UTF-8'?>
 <painting>
   <img src="madonna.jpg" alt='Foligno Madonna, by Raphael'/>
   <caption>This is Raphael's "Foligno" Madonna, painted in
   <date>1511</date>-<date>1512</date>.</caption>
 </painting>
EOF

あなたはほとんどそこにいます。文字列のアセンブリにcatを使用するか、文字列全体を引用します(この場合、文字列内の引用符をエスケープする必要があります):

#!/bin/sh
VAR1=$(cat <<EOF
<?xml version="1.0" encoding='UTF-8'?>
<painting>
  <img src="madonna.jpg" alt='Foligno Madonna, by Raphael'/>
  <caption>This is Raphael's "Foligno" Madonna, painted in
  <date>1511</date>-<date>1512</date>.</caption>
</painting>
EOF
)

VAR2="<?xml version=\"1.0\" encoding='UTF-8'?>
<painting>
  <img src=\"madonna.jpg\" alt='Foligno Madonna, by Raphael'/>
  <caption>This is Raphael's \"Foligno\" Madonna, painted in
  <date>1511</date>-<date>1512</date>.</caption>
</painting>"

echo "${VAR1}"
echo "${VAR2}"
27
joschi
#!/bin/sh

VAR1=`cat <<EOF
<?xml version="1.0" encoding='UTF-8'?>
<painting>
  <img src="madonna.jpg" alt='Foligno Madonna, by Raphael'/>
  <caption>This is Raphael's "Foligno" Madonna, painted in
  <date>1511</date>-<date>1512</date>.</caption>
</painting>
EOF
`
echo "VAR1: ${VAR1}"

これはBourne Shell環境内で正常に動作するはずです

14
schweiz

同じことをするさらに別の方法...

変数と特別な<<-を使用して、各行の先頭にtabulationをドロップし、スクリプトのインデントを許可します。

#!/bin/bash

mapfile Pattern <<-eof
        <?xml version="1.0" encoding='UTF-8'?>
        <painting>
          <img src="%s" alt='%s'/>
          <caption>%s, painted in
          <date>%s</date>-<date>%s</date>.</caption>
        </painting>
        eof

while IFS=";" read file alt caption start end ;do
    printf "${Pattern[*]}" "$file" "$alt" "$caption" "$start" "$end"
  done <<-eof
        madonna.jpg;Foligno Madonna, by Raphael;This is Raphael's "Foligno" Madonna;1511;1512
        eof

警告eofの前には空白はありませんが、のみです集計

<?xml version="1.0" encoding='UTF-8'?>
 <painting>
   <img src="madonna.jpg" alt='Foligno Madonna, by Raphael'/>
   <caption>This is Raphael's "Foligno" Madonna, painted in
   <date>1511</date>-<date>1512</date>.</caption>
 </painting>
  • mapfileは配列内のhere document全体を読み取ります。
  • 構文"${Pattern[*]}"は、この配列を文字列にキャストします。
  • 必要な文字列にIFS=";"がないため、;を使用します
  • 構文while IFS=";" read file ...は、スクリプトの残りの部分でIFSが変更されるのを防ぎます。この場合、変更されたreadを使用するのはIFSだけです。
  • フォークはありません。
6
F. Hauri

他の多くの回答では、コーナーケースが多すぎます。

スペース、タブ、IFSなどの問題がないことを完全に確認するには、「heredoc」コンストラクトを使用することをお勧めしますが、ここで説明するように、uuencodeを使用してheredocのコンテンツをエンコードします。

https://stackoverflow.com/questions/6896025/#11379627

2
Chris Johnson