HEREDOCテキストをシェルスクリプト変数にどのように入れますか?

HEREDOCテキストをシェルスクリプト変数にどのように入れますか?

POSIX互換の方法でHEREDOCテキストをシェルスクリプト変数に入れようとしています。私はそう試みる:

#!/bin/sh

NEWLINE="
"

read_heredoc2() {
  while IFS="$NEWLINE" read -r read_heredoc_line; do
    echo "${read_heredoc_line}"
  done
}

read_heredoc2_result="$(read_heredoc2 <<'HEREDOC'

                        _                            _ _
                       | |                          | (_)
  _ __ ___  _   _ _ __ | | __ _  ___ ___  ___  _ __ | |_ _ __   ___
 | '_ ` _ \| | | | '_ \| |/ _` |/ __/ _ \/ _ \| '_ \| | | '_ \ / _ \
 | | | | | | |_| | |_) | | (_| | (_|  __/ (_) | | | | | | | | |  __/
 |_| |_| |_|\__, | .__/|_|\__,_|\___\___|\___/|_| |_|_|_|_| |_|\___|
             __/ | |
            |___/|_|



HEREDOC
)"

echo "${read_heredoc2_result}"

これにより、次のエラーが発生しました。

                        _                            _ _
                       | |                          | (_)
  _ __ ___  _   _ _ __ | | __ _  ___ ___  ___  _ __ | |_ _ __   ___
 | '_ ` _ \| | | | '_ \| |/ _` |/ __/ _ \/ _ \| '_ \| | | '_ \ / _  | | | | | | |_| | |_) | | (_| | (_|  __/ (_) | | | | | | | | |  __/
 |_| |_| |_|\__, | .__/|_|\__,_|\___\___|\___/|_| |_|_|_|_| |_|\___|
             __/ | |
            |___/|_|

次の方法はうまくいきますが、ランダムな出力変数を使用するのがどれほど扱いにくいのか気にしません。

#!/bin/sh

NEWLINE="
"

read_heredoc1() {
  read_heredoc_first=1
  read_heredoc_result=""
  while IFS="$NEWLINE" read -r read_heredoc_line; do
    if [ ${read_heredoc_first} -eq 1 ]; then
      read_heredoc_result="${read_heredoc_line}"
      read_heredoc_first=0
    else
      read_heredoc_result="${read_heredoc_result}${NEWLINE}${read_heredoc_line}"
    fi
  done
}

read_heredoc1 <<'HEREDOC'

                        _                            _ _            
                       | |                          | (_)           
  _ __ ___  _   _ _ __ | | __ _  ___ ___  ___  _ __ | |_ _ __   ___ 
 | '_ ` _ \| | | | '_ \| |/ _` |/ __/ _ \/ _ \| '_ \| | | '_ \ / _ \
 | | | | | | |_| | |_) | | (_| | (_|  __/ (_) | | | | | | | | |  __/
 |_| |_| |_|\__, | .__/|_|\__,_|\___\___|\___/|_| |_|_|_|_| |_|\___|
             __/ | |                                                
            |___/|_|                                                



HEREDOC

echo "${read_heredoc_result}"

正しい出力:

                        _                            _ _            
                       | |                          | (_)           
  _ __ ___  _   _ _ __ | | __ _  ___ ___  ___  _ __ | |_ _ __   ___ 
 | '_ ` _ \| | | | '_ \| |/ _` |/ __/ _ \/ _ \| '_ \| | | '_ \ / _ \
 | | | | | | |_| | |_) | | (_| | (_|  __/ (_) | | | | | | | | |  __/
 |_| |_| |_|\__, | .__/|_|\__,_|\___\___|\___/|_| |_|_|_|_| |_|\___|
             __/ | |                                                
            |___/|_|                                                

どんなアイデアがありますか?

ベストアンサー1

問題は、大きな打撃を受けた状態で、内部$( ... )エスケープ(およびその他)シーケンスは、区切り文字自体にそのシーケンスがない場合でも構文解析されます。改行文字がエスケープされているため、二重線\が表示されます。あなたが見ているのは実際にBashの解析問題です。他のシェルではこれを行いません。バックティックは以前のバージョンでも問題になる可能性があります。私は持っていますこれがBashのバグであることを確認しました。、今後のバージョンで修正される予定です。

少なくとも機能を大幅に簡素化できます。

func() {
    res=$(cat)
}
func <<'HEREDOC'
...
HEREDOC

出力変数を選択するにはパラメータ化できます。

func() {
    eval "$1"'=$(cat)'
}
func res<<'HEREDOC'
...
HEREDOC

または、次のことがないやや醜いものeval

{ res=$(cat) ; } <<'HEREDOC'
...
HEREDOC

必要なのは、後で変数を引き続き使用できるようにすることで{}はありません。()

これをどれだけ頻繁に実行し、どの目的で実行するかに応じて、1つまたは他のオプションを好むことができます。最後は最も簡潔なワンタイムです。


が利用可能な場合、zsh元のコマンドの置き換え+ heredocはそのまま機能しますが、これらの項目をさらに縮小することもできます。

x=$(<<'EOT'
...
EOT
)

Bashはこれをサポートしておらず、他のシェルにはあなたが持っている問題がないと思います。

おすすめ記事