web-dev-qa-db-ja.com

余分なスペースを持つ複数行の文字列(字下げを維持)

次のように定義済みのテキストをファイルに書き込みます。

text="this is line one\n
this is line two\n
this is line three"

echo -e $text > filename

私はこのような何かを期待しています:

this is line one
this is line two
this is line three

しかし、これを得ました:

this is line one
 this is line two
 this is line three

私はそれぞれの\nの後にスペースがないことを確信しています、しかしどのように余分なスペースが出ますか?

292
cizixs

Heredocはこの目的のためにより便利に聞こえます。 ex または cat のようなコマンドインタプリタプログラムに複数のコマンドを送るために使用されます。

cat << EndOfMessage
This is line 1.
This is line 2.
Line 3.
EndOfMessage

<<の後の文字列は、停止する場所を示します。

これらの行をファイルに送信するには、次のようにします。

cat > $FILE <<- EOM
Line 1.
Line 2.
EOM

これらの行を変数に格納することもできます。

read -r -d '' VAR << EOM
This is line 1.
This is line 2.
Line 3.
EOM

これは行をVARという名前の変数に格納します。

印刷するときは、変数を囲む引用符を忘れないでください。そうしないと、改行文字が表示されません。

echo "$VAR"

さらに良いことには、インデントを使ってコードの中でもっと目立つようにすることができます。今度はタブが表示されないようにするために-の後に<<を追加するだけです。

read -r -d '' VAR <<- EOM
    This is line 1.
    This is line 2.
    Line 3.
EOM

しかし、その場合は、コード内のインデントのためにスペースではなくタブを使用する必要があります。

490
new-kid

あなたが変数に文字列を取得しようとしているなら、もう一つの簡単な方法はこのようなものです:

USAGE=$(cat <<-END
    This is line one.
    This is line two.
    This is line three.
END
)

タブで文字列をインデントすると(つまり '\ t')、インデントは削除されます。スペースでインデントすると、インデントは残ります。

注:最後の閉じ括弧が別の行にあることは、 - - 意味です。 ENDのテキストはそれ自身で行に現れなければなりません。

116
Andrew Miner

echoは、渡された引数の間にスペースを追加します。 $textは変数展開とWord分割の影響を受けるので、echoコマンドは次のものと同等です。

echo -e "this" "is" "line" "one\n" "this" "is" "line" "two\n"  ...

"this"の前にスペースが追加されることがわかります。改行文字を削除して、改行を保持するために$textを引用することができます。

text="this is line one
this is line two
this is line three"

echo "$text" > filename

あるいはprintfを使用することもできます。これはechoよりも堅牢で移植性があります。

printf "%s\n" "this is line one" "this is line two" "this is line three" > filename

ブレース展開をサポートしているbashでは、次のようなこともできます。

printf "%s\n" "this is line "{one,two,three} > filename
66
Josh Jolly

bashスクリプトでは、次のように動作します。

#!/bin/sh

text="this is line one\nthis is line two\nthis is line three"
echo $text > filename

あるいは:

text="this is line one
this is line two
this is line three"
echo "$text" > filename

cat filenameは次のようになります。

this is line one
this is line two
this is line three
35
Chris Maes

すべての行を適切にインデントしたいので、もっと多くの解決策を見つけました。

  1. echoを使うことができます:

    echo    "this is line one"   \
        "\n""this is line two"   \
        "\n""this is line three" \
        > filename
    

    "\n"を行末の\の直前に置いた場合はうまくいきません。

  2. 別の方法として、移植性を高めるためにprintfを使用することもできます(私はechoに関して多くの問題を抱えていました)。

    printf '%s\n' \
        "this is line one"   \
        "this is line two"   \
        "this is line three" \
        > filename
    
  3. さらに別の解決策があります:

    text=''
    text="${text}this is line one\n"
    text="${text}this is line two\n"
    text="${text}this is line three\n"
    printf "%b" "$text" > filename
    

    または

    text=''
    text+="this is line one\n"
    text+="this is line two\n"
    text+="this is line three\n"
    printf "%b" "$text" > filename
    
  4. 別の解決策はprintfsedを混在させることによって達成されます。

    if something
    then
        printf '%s' '
        this is line one
        this is line two
        this is line three
        ' | sed '1d;$d;s/^    //g'
    fi
    

    インデントレベルをコードにハードコードするので、このようにフォーマットされたコードをリファクタリングするのは簡単ではありません。

  5. ヘルパー関数といくつかの変数置換トリックを使うことは可能です。

    unset text
    _() { text="${text}${text+
    }${*}"; }
    # That's an empty line which demonstrates the reasoning behind 
    # the usage of "+" instead of ":+" in the variable substitution 
    # above.
    _ ""
    _ "this is line one"
    _ "this is line two"
    _ "this is line three"
    unset -f _
    printf '%s' "$text"
    
30

以下は、複数行の文字列を変数に代入するための私の望ましい方法です(私はそれがいいと思う)。

read -r -d '' my_variable << \
_______________________________________________________________________________

String1
String2
String3
...
StringN
_______________________________________________________________________________

どちらの場合も、アンダースコアの数は同じです(ここでは80)。

1

あなたが以下のようにそれを置けばそれは動作します:

AA='first line
\nsecond line 
\nthird line'
echo $AA
output:
first line
second line
third line
1
luk