Bashで複数行の文字列を出力する方法は?


250

次のように複数のエコー呼び出しを使用せずにBashで複数行の文字列を出力するにはどうすればよいですか。

echo "usage: up [--level <n>| -n <levels>][--help][--version]"
echo 
echo "Report bugs to: "
echo "up home page: "

Bashビルトインのみを使用して、これを実行するポータブルな方法を探しています。


4
あなたは間違って呼び出しに応答した使用方法のメッセージを出力している場合は、通常ではなく、標準出力、標準エラー出力にそのメッセージを送信しますecho >&2 ...
マーク・リード

2
@MarkReed入力すると、使用法のメッセージが出力されます--help(標準出力に移動するはずです)。
helpermethod

来た人のために、「ヒアドキュメント」についてのより多くの情報が利用可能です:tldp.org/LDP/abs/html/here-docs.html
Jeffrey Martinez

printfGordon Davidsonの-ベースのソリューションを確認してください。echoまたはcatベースのアプローチの陰にあるにもかかわらず、それはクラッジのはるかに少ないようです。確かに、 `printf '構文は少し学習曲線を表していますが、他の欠点(?互換性、パフォーマンス?...)を聞きたいと思います
mjv

回答:


296

ここでは、ドキュメントがこの目的でよく使用されます。

cat << EOF
usage: up [--level <n>| -n <levels>][--help][--version]

Report bugs to: 
up home page:
EOF

これらは、Bashのすべてのバージョンを含む、すべてのBourne派生シェルでサポートされています。


4
うん- cat組み込みではありません。
Mark Reed、

8
@MarkReed:それは本当ですが、それは常に利用可能です(例外的な状況下を除いて)。
追って通知があるまで一時停止。

6
+1 Thx。を使用read -d '' help <<- EOF ...して、複数行の文字列を変数に読み込み、結果をエコーし​​ました。
ヘルパーメソッド'10年

3
HEREDOCを変数に保存できますか?
2015

177

またはこれを行うことができます:

echo "usage: up [--level <n>| -n <levels>][--help][--version]

Report bugs to: 
up home page: "

1
@OliverWeiler:DashやHeirloom Bourne ShellなどのBourneシェルでも機能します。
追って通知があるまで一時停止。

6
これを関数で必要とする場合は、1)ファイルの左端まで文字列をインデント解除するか、2)インデントを維持してコードの残りの部分に合わせてください。インデントも
sg

43

このページの洞察に満ちた答えに触発されて、私は混合アプローチを作成しました。これは、最も単純でより柔軟なアプローチと考えています。どう思いますか?

最初に、変数の使用法を定義します。これにより、さまざまなコンテキストで再利用できます。形式は非常にシンプルで、ほとんどWYSIWYGで、制御文字を追加する必要はありません。これは私にはかなり移植性があるようです(MacOSとUbuntuで実行しました)。

__usage="
Usage: $(basename $0) [OPTIONS]

Options:
  -l, --level <n>              Something something something level
  -n, --nnnnn <levels>         Something something something n
  -h, --help                   Something something something help
  -v, --version                Something something something version
"

次に、単純にそれを次のように使用できます

echo "$__usage"

またはさらに良いことに、パラメーターを解析するときに、1行でエコーすることができます。

levelN=${2:?"--level: n is required!""${__usage}"}

4
これは、上記の答えが(変更なしで)機能しないスクリプトで私にとってはうまくいきました。
デビッドウェルチ

3
これは、テキストで見つけるのが難しい\ tや\ nなどの一連の文字を使用するよりもはるかにクリーンで、スクリプト内の文字列とは大きく異なるように拡張して出力します
sg

1
なんらかの理由で、すべてが同じ行に出力されます:/
Nicolas de Fontenay

2
@Nicolas:で二重引用符を使用echo "$__usage"する必要がありました。echo $__usage動作しませんでした。
マリオ

24

-eオプションを使用する\nと、文字列に改行文字を印刷できます。

サンプル(良いものかどうかはわかりません)

おもしろいことに、この-eオプションはまだ使用可能ですが、MacOSのmanページに記載されていません。Linuxmanページに記載されています


6
これらのmanページは、システム提供のechoコマンドで/bin/echo、Mac OSでは-eオプションがありません。これらのシステムでbashを使用している場合は、その組み込みechoコマンドが引き継ぎます。これを確認/bin/echo whateverするには、動作の違いを明示的に入力して観察します。組み込みのドキュメントを表示するには、と入力しhelp echoます。
マークリード

1
/bin/echo多くの場合、OSごとに異なり、Bashの組み込みとも異なりechoます。
追って通知があるまで一時停止。

@MarkReed:後で試してみるが、情報をありがとう。+1。かなり多くの良い議論が行われているので、私はここで私の答えをそのままにしておきます。
nhahtdh

7
echo -e移植性はありません。たとえば、echoの一部の実装では、出力の一部として「-e」が出力されます。移植性が必要な場合は、代わりにprintfを使用してください。たとえば、OS X 10.7.4の/ bin / echoはこれを行います。IIRC bashビルトインエコーも10.5.0で奇妙でしたが、詳細はもう覚えていません。
Gordon Davisson

2
echo -e前に私を噛んだ...間違いなく、printfまたはcatヒアドキュメントと一緒に使用します。<<-ここのドキュメントのバリアントは、出力の先頭のインデントを取り除くことができるので特に便利ですが、スクリプトでは読みやすくするためにインデントします
zbeekman

22

printfコメントで推奨しているので、おそらくその使用例をいくつか示す必要があります(使用方法のメッセージを印刷する場合は、DennisまたはChrisの回答を使用する可能性が高くなります)。 printfを使用するよりも少し複雑ですecho。最初の引数はフォーマット文字列で、エスケープ(など\n)は常に解釈されます。また%、で始まるフォーマットディレクティブを含めることもできます。このディレクティブは、追加の引数が含まれる場所と方法を制御します。使用法メッセージに使用する2つの異なる方法を次に示します。

まず、メッセージ全体をフォーマット文字列に含めることができます。

printf "usage: up [--level <n>| -n <levels>][--help][--version]\n\nReport bugs to: \nup home page: \n"

とは異なりecho、最後の改行を明示的に含める必要があることに注意してください。また、メッセージにたまたま%文字が含まれている場合は、と書く必要があります%%。バグレポートとホームページのアドレスを含めたい場合は、自然に追加できます。

printf "usage: up [--level <n>| -n <levels>][--help][--version]\n\nReport bugs to: %s\nup home page: %s\n" "$bugreport" "$homepage"

次に、フォーマット文字列を使用して、追加の各引数を別々の行に出力することができます。

printf "%s\n" "usage: up [--level <n>| -n <levels>][--help][--version]" "" "Report bugs to: " "up home page: "

このオプションを使用すると、バグレポートとホームページのアドレスを追加することはかなり明白です。

printf "%s\n" "usage: up [--level <n>| -n <levels>][--help][--version]" "" "Report bugs to: $bugreport" "up home page: $homepage"

9

また、インデントされたソースコードを使用する<<-と、(末尾のダッシュを付けて)先頭のタブを無視できます(ただし、先頭のスペースは無視できます)。例えばこれは:

if [ some test ]; then
    cat <<- xx
        line1
        line2
xx
fi

先頭の空白なしでインデントされたテキストを出力します。

line1
line2

それは私にはうまくいきませんでした。どのシェルを使用していますか?
four43

Ubuntuのbash 4.4.19では機能しませんでした。line1と
line2の

1
@ four43、あなたは正しかった。先頭のスペースを削除する機能はありません。ただし、先頭のタブは削除されます。そこで、タブとスペースからタブではなくスペースに私の答えを修正しました。間違いでごめんなさい。私はマニュアルを確認しましたが、タブが削除されたとはっきり書いてあります。これを私の注意を喚起してくれてありがとう。
楕円図

0

@jorgeのソリューションを使用して、すべてが同じ行にあることがわかった場合は、変数を引用符で囲んでください。

echo $__usage

すべてを1行で印刷しますが、

echo "$__usage"

改行を保持します。


これは実際に私のために働いた1つの解決策です。Printfは多くのことを行いますが、私の複数行のxmlでは、コンテンツを完全に破壊するため、おそらく多くのエスケープが必要です。私はfoo = cat <<EOF .... EOF&& echo "$ foo" を割り当てます
Jilles van Gurp
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.