バッシュ継続行


158

bash継続行をどのように使用しますか?

私はあなたがこれを行うことができることを理解しています:

echo "continuation \
lines"
>continuation lines

ただし、インデントされたコードがある場合、うまく機能しません。

    echo "continuation \
    lines"
>continuation     lines

5
GoogleのBashシェルスタイルガイドでは、「 80文字を超える文字列を記述する必要がある場合」に「ここ」のドキュメント推奨しています。@tripleeeの回答を参照してください。
Trevor Boyd Smith

google.github.io/styleguide/…-これは、新しいドキュメントへの直接リンクです
jcollum

回答:


161

これはあなたが望むかもしれないことです

$       echo "continuation"\
>       "lines"
continuation lines

これがエコーする2つの引数を作成し、1つだけが必要な場合は、文字列の連結を見てみましょう。bashでは、2つの文字列を互いに隣接して配置します。

$ echo "continuation""lines"
continuationlines

したがって、インデントのない継続行は、文字列を分割する 1つの方法です。

$ echo "continuation"\
> "lines"
continuationlines

しかし、インデントが使用されている場合:

$       echo "continuation"\
>       "lines"
continuation lines

これはもはや連結ではないため、2つの引数が得られます。

行を横切る単一の文字列が必要で、インデントはしているがすべてのスペースは取得していない場合は、継続行を破棄して変数を使用する方法があります。

$ a="continuation"
$ b="lines"
$ echo $a$b
continuationlines

これにより、追加の変数を犠牲にして、コードをきれいにインデントすることができます。変数をローカルにすると、悪くないはずです。


1
ご協力ありがとうございます。ただし、これによりスペースは削除されますが、これらは個別のパラメーターになり(Bashは2行目のスペースをパラメーターセパレーターとして解釈します)、echoコマンドにより正しく印刷されるようになりました。

1
ああ、あなたは単一の(bash)文字列が複数の行にまたがることを望みます!なるほど。
Ray Toal

4
1つの変数を使用したソリューション:s="string no. 1" s+="string no. 2" s+=" string no. 3" echo "$s"
Johnny Thunderman

30

ここで、<<-HEREターミネータ付きのドキュメントは、インデントされた複数行のテキスト文字列に適しています。ヒアドキュメントから先頭のタブを削除します。(ただし、ラインターミネータは残ります)。

cat <<-____HERE
    continuation
    lines
____HERE

http://ss64.com/bash/syntax-here.htmlも参照してください

すべてではなく一部の先頭の空白を保持する必要がある場合は、次のようなものを使用できます

sed 's/^  //' <<____HERE
    This has four leading spaces.
    Two of them will be removed by sed.
____HERE

または多分tr改行を取り除くために使用します:

tr -d '\012' <<-____
    continuation
     lines
____

(2行目には前にタブとスペースがあります。タブは、ヒアドキュメントのターミネーターの前にダッシュ演算子によって削除されますが、スペースは保持されます。)

長い複雑な文字列を多くの行でラップするために、私は好きprintfです:

printf '%s' \
    "This will all be printed on a " \
    "single line (because the format string " \
    "doesn't specify any newline)"

また、あなたがそのようなのように、ここで文書を使用しますが、ホスト言語の構文はさせません別の言語でのシェルスクリプトの埋め込み自明でない作品にしたい場面でうまく動作しますMakefileDockerfile

printf '%s\n' >./myscript \
    '#!/bin/sh` \
    "echo \"G'day, World\"" \
    'date +%F\ %T' && \
chmod a+x ./myscript && \
./myscript

私にはうまくいきません。Ubuntu 16.04。予想される連結された1行ではなく、2行が表示されます。
Penghe Geng

@PengheGeng確かに、これはインデントを取り除くという問題を解決するものであり、行を結合する問題ではありません。行末で改行をバックスラッシュして、2つの行を結合することもできます。
Tripleee、2018

(しかし、最初のprintf例も今すぐ参照してください。)
tripleee

12

bash配列を使用できます

$ str_array=("continuation"
             "lines")

その後

$ echo "${str_array[*]}"
continuation lines

(bashマニュアルの後)ので、余分なスペースがあります。

単語が二重引用符で囲まれ${name[*]}ている場合、各配列メンバーの値がIFS変数の最初の文字で区切られた単一の単語に展開されます

だからIFS=''余分なスペースを取り除くために設定

$ IFS=''
$ echo "${str_array[*]}"
continuationlines

4

Bashの連結機能を利用する特定のシナリオでは、適切な場合があります。

例:

temp='this string is very long '
temp+='so I will separate it onto multiple lines'
echo $temp
this string is very long so I will separate it onto multiple lines

Bash ManページのPARAMETERSセクションから:

名前= [値] ...

...割り当てステートメントがシェル変数または配列インデックスに値を割り当てるコンテキストでは、+ =演算子を使用して、変数の以前の値に追加または追加できます。+ =が整数属性が設定されている変数に適用されると、valueは算術式として評価され、変数の現在の値に追加されます。これも評価されます。+ =が複合代入を使用して配列変数に適用される場合(以下の配列を参照)、変数の値は設定解除されず(=を使用する場合のように)、新しい値が配列の最大インデックスよりも大きい値で始まる配列に追加されます(インデックス付き配列の場合)、または連想配列のキーと値のペアとして追加されます。 文字列値の変数に適用されると、値は展開され、変数の値に追加されます。


おそらくこのページで最高のアドバイスです。HEREDOCを使用して<CR>の変換にパイプすることは非常に直感的でなく、文字列に実際に個別に配置された行区切り文字が必要な場合は失敗します。
1

2

コマンド引数の一部として長いメッセージを送信しなければならず、行の長さの制限を遵守しなければならない状況に遭遇しました。コマンドは次のようになります。

somecommand --message="I am a long message" args

私がこれを解決した方法は、メッセージをヒアドキュメント(@tripleeeのような)として移動することです。しかし、ヒアドキュメントは標準入力になるので、それを読み戻す必要があるので、以下のアプローチを採用しました:

message=$(
    tr "\n" " " <<- END
        This is a
        long message
END
)
somecommand --message="$message" args

これには、$message余分な空白や改行なしで文字列定数とまったく同じように使用できるという利点があります。

上記の実際のメッセージ行には、tabそれぞれ文字がプレフィックスとして付けられていることに注意してください。これは、(を使用しているため)ドキュメント自体によって削除されます<<-。末尾にはまだ改行がありdd、スペースで置き換えられます。

また、改行を削除しないと、"$message"が展開されたときにそのまま表示されます。場合によっては、の二重引用符を削除することで回避できること$messageがありますが、メッセージは単一の引数ではなくなります。


2

構文の巧妙な使用により、行の継続も実現できます。

の場合echo

# echo '-n' flag prevents trailing <CR> 
echo -n "This is my one-line statement" ;
echo -n " that I would like to make."
This is my one-line statement that I would like to make.

varsの場合:

outp="This is my one-line statement" ; 
outp+=" that I would like to make." ; 
echo -n "${outp}"
This is my one-line statement that I would like to make.

変数の場合の別のアプローチ:

outp="This is my one-line statement" ; 
outp="${outp} that I would like to make." ; 
echo -n "${outp}"
This is my one-line statement that I would like to make.

出来上がり!


1

次のように、インデント内で必要に応じて、単に(バックスラッシュを使用せずに)改行で区切ることができ、新しい行を削除します。

例:

echo "continuation
of 
lines" | tr '\n' ' '

または、変数定義の場合、改行は自動的にスペースに変換されます。そのため、該当する場合にのみ、余分なスペースを取り除いてください。

x="continuation
of multiple
lines"
y="red|blue|
green|yellow"

echo $x # This will do as the converted space actually is meaningful
echo $y | tr -d ' ' # Stripping of space may be preferable in this case

1

これは正確にはユーザーが求めたものではありませんが、複数行にまたがる長い文字列を作成する別の方法は、次のように徐々に構築することです。

$ greeting="Hello"
$ greeting="$greeting, World"
$ echo $greeting
Hello, World

この場合は、一回で作成する方が簡単だったのは明らかですが、このスタイルは非常に軽量で、長い文字列を処理するときに理解できます。


0

ただし、インデントされたコードがある場合、うまく機能しません。

    echo "continuation \
    lines"
>continuation     lines

一重引用符で試し、文字列を連結します。

    echo 'continuation' \
    'lines'
>continuation lines

注:連結には空白が含まれます。


2
エコーと文字列の引数で機能しますが、変数の割り当てなど、他のものでは機能しません。問題は変数に関するものではありませんでしたが、エコーの使用は単なる例でした。があったecho 場合の代わりに x=、エラーが発生しますlines: command not found
LS

0

受け入れるリスクの種類と、データをどの程度よく理解して信頼するかに応じて、単純な変数補間を使用できます。

$: x="
    this
    is
       variably indented
    stuff
   "
$: echo "$x" # preserves the newlines and spacing

    this
    is
       variably indented
    stuff

$: echo $x # no quotes, stacks it "neatly" with minimal spacing
this is variably indented stuff

-2

これはおそらくあなたの質問に実際には答えませんが、とにかくそれが役に立つかもしれません。

最初のコマンドは、2番目のコマンドによって表示されるスクリプトを作成します。

3番目のコマンドは、そのスクリプトを実行可能にします。

4番目のコマンドは、使用例を提供します。

john@malkovich:~/tmp/so$ echo $'#!/usr/bin/env python\nimport textwrap, sys\n\ndef bash_dedent(text):\n    """Dedent all but the first line in the passed `text`."""\n    try:\n        first, rest = text.split("\\n", 1)\n        return "\\n".join([first, textwrap.dedent(rest)])\n    except ValueError:\n        return text  # single-line string\n\nprint bash_dedent(sys.argv[1])'  > bash_dedent
john@malkovich:~/tmp/so$ cat bash_dedent 
#!/usr/bin/env python
import textwrap, sys

def bash_dedent(text):
    """Dedent all but the first line in the passed `text`."""
    try:
        first, rest = text.split("\n", 1)
        return "\n".join([first, textwrap.dedent(rest)])
    except ValueError:
        return text  # single-line string

print bash_dedent(sys.argv[1])
john@malkovich:~/tmp/so$ chmod a+x bash_dedent
john@malkovich:~/tmp/so$ echo "$(./bash_dedent "first line
>     second line
>     third line")"
first line
second line
third line

このスクリプトを本当に使用したい場合は、実行可能スクリプトをに移動~/binして、パスに含める方が理にかなっていることに注意してください。

textwrap.dedent動作の詳細については、Pythonリファレンスを確認してください。

の使用法$'...'または"$(...)"混乱を招く場合は、(構成ごとに1つずつ)別の質問をして、まだ問題がないか確認してください。他の人がリンクされた参照を持つように、あなたが見つけたり質問したりする質問へのリンクを提供するとよいでしょう。


6
よく意図されていて、おそらく役に立つかもしれませんが、OPは基本的なbash構文についてアドバイスを求め、OOパラダイム、例外的なフロー制御、およびインポートを使用するpython関数定義を彼に与えました。さらに、文字列補間の一部として実行可能ファイルを呼び出しました。この種の質問をする人がbashではまだ見たことがないものです。
パルティアンショット
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.