web-dev-qa-db-ja.com

shの文字列に改行を含めるにはどうすればよいですか?

この

STR="Hello\nWorld"
echo $STR

出力として生成

Hello\nWorld

の代わりに

Hello
World

文字列に改行を含めるにはどうすればよいですか?

注:この質問はechoではありません。echo -eは知っていますが、次のような解決策を探しています。 \nを改行として解釈する同様のオプションを持たないotherコマンドへの引数として文字列(改行を含む)を渡すことができます。

288
Juan A. Navarro

解決策は$'string'を使うことです、例えば:

$ STR=$'Hello\nWorld'
$ echo "$STR"
Hello
World

これがBashのマニュアルページからの抜粋です。

   Words of the form $'string' are treated specially.  The Word expands to
   string, with backslash-escaped characters replaced as specified by  the
   ANSI  C  standard.  Backslash escape sequences, if present, are decoded
   as follows:
          \a     alert (bell)
          \b     backspace
          \e
          \E     an escape character
          \f     form feed
          \n     new line
          \r     carriage return
          \t     horizontal tab
          \v     vertical tab
          \\     backslash
          \'     single quote
          \"     double quote
          \nnn   the eight-bit character whose value is  the  octal  value
                 nnn (one to three digits)
          \xHH   the  eight-bit  character  whose value is the hexadecimal
                 value HH (one or two hex digits)
          \cx    a control-x character

   The expanded result is single-quoted, as if the  dollar  sign  had  not
   been present.

   A double-quoted string preceded by a dollar sign ($"string") will cause
   the string to be translated according to the current  locale.   If  the
   current  locale  is  C  or  POSIX,  the dollar sign is ignored.  If the
   string is translated and replaced, the replacement is double-quoted.
285
amphetamachine

Echoはとても90年代で危険をはらんでいるので、その使用は4GB以上のコアダンプをもたらすはずです。真剣に、echoの問題が、Unix標準化プロセスがついにprintfユーティリティを発明し、すべての問題を排除した理由でした。

だから、文字列で改行を取得する:

FOO="hello
world"
BAR=$(printf "hello\nworld\n") # Alternative; note: final newline is deleted
printf '<%s>\n' "$FOO"
printf '<%s>\n' "$BAR"

そこ! SYSVとBSDの反響はありません。すべてがきれいに印刷され、Cのエスケープシーケンスを完全にポータブルにサポートします。誰もが今printfを使ってください、そして決して振り返らないでください。

145
Jens

他の答えに基づいて私がしたことは

NEWLINE=$'\n'
my_var="__between eggs and bacon__"
echo "spam${NEWLINE}eggs${my_var}bacon${NEWLINE}knight"

# which outputs:
spam
eggs__between eggs and bacon__bacon
knight
48
zvezda

問題はシェルにはありません。問題は実際にはechoコマンド自体、および変数の内挿を囲む二重引用符の欠如です。 echo -eを使ってみることもできますが、それはすべてのプラットフォームでサポートされているわけではないので、移植性の観点からprintfが推奨される理由の1つです。

シェルスクリプトに直接改行を挿入して試してみることもできます(スクリプトが現在作成しているものである場合)。そのように見えます...

#!/bin/sh
echo "Hello
World"
#EOF

または同等に

#!/bin/sh
string="Hello
World"
echo "$string"  # note double quotes!
26
Pace
  1. 唯一の簡単な方法は、実際に変数に新しい行を入力することです。

    $ STR='new
    line'
    $ printf '%s' "$STR"
    new
    line
    

    はい、それは書くことを意味します Enter コードの必要な箇所.

  2. new line文字に相当するものがいくつかあります。

    \n           ### A common way to represent a new line character.
    \012         ### Octal value of a new line character.
    \x0A         ### Hexadecimal value of a new line character.
    

    しかし、それらすべては何らかのツールによる「解釈」を必要とします( POSIX printf ):

    echo -e "new\nline"           ### on POSIX echo, `-e` is not required.
    printf 'new\nline'            ### Understood by POSIX printf.
    printf 'new\012line'          ### Valid in POSIX printf.
    printf 'new\x0Aline'       
    printf '%b' 'new\0012line'    ### Valid in POSIX printf.
    

    したがって、ツールは改行を含む文字列を作成する必要があります。

    $ STR="$(printf 'new\nline')"
    $ printf '%s' "$STR"
    new
    line
    
  3. いくつかのシェルでは、 $' 特別なシェル展開です。 ksh93、bash、zshで動作することが知られています。

    $ STR=$'new\nline'
    
  4. もちろん、もっと複雑な解決策も可能です。

    $ echo '6e65770a6c696e650a' | xxd -p -r
    new
    line
    

    または

    $ echo "new line" | sed 's/ \+/\n/g'
    new
    line
    
19
user2350426

-eフラグはエレガントで率直なものです。

bash$ STR="Hello\nWorld"

bash$ echo -e $STR
Hello
World

文字列が他のコマンドの出力である場合は、引用符を使用します

indexes_diff=$(git diff index.yaml)
echo "$indexes_diff"
11
Simon Ndunda

次のように単一引用符 '...\n ...'の直前に$を付けますが、二重引用符は機能しません。

$ echo $'Hello\nWorld'
Hello
World
$ echo $"Hello\nWorld"
Hello\nWorld
4
caot

私はbashの専門家ではありませんが、これは私のために働きました:

STR1="Hello"
STR2="World"
NEWSTR=$(cat << EOF
$STR1

$STR2
EOF
)
echo "$NEWSTR"

私はこれをテキストの書式設定の方が簡単だと感じました。

3
Jason

改行だけを必要とし、インデントを破る複数行コードを軽蔑するような気の利いた人は、次のことができます。

IFS="$(printf '\nx')"
IFS="${IFS%x}"

Bash(そしておそらく他のシェルも)はコマンド置換後のすべての末尾の改行を削除するので、printfの文字列は改行以外の文字で終わらせ、その後それを削除する必要があります。これはまた簡単にonelinerになることができます。

IFS="$(printf '\nx')" IFS="${IFS%x}"

私はこれが1つではなく2つのアクションであることを知っていますが、私のインデントと移植性OCDは今は平和です:)私はもともと改行のみで区切られた出力を分割できるようにこれを開発し、終了文字として\rを使う修正を使いました。これにより、\r\nで終わるdos出力に対しても改行分割が機能するようになります。

IFS="$(printf '\n\r')"
0
tlwhitec

私はここのオプションのどれにも本当に満足していませんでした。これは私のために働いたものです。

str=$(printf "%s" "first line")
str=$(printf "$str\n%s" "another line")
str=$(printf "$str\n%s" "and another line")
0
Adam K Dean

私のシステム(Ubuntu 17.10)では、コマンドラインから(shに)入力したときとshスクリプトとして実行したときの両方で、この例は望みどおりに動作します。

[bash]§ sh
$ STR="Hello\nWorld"
$ echo $STR
Hello
World
$ exit
[bash]§ echo "STR=\"Hello\nWorld\"
> echo \$STR" > test-str.sh
[bash]§ cat test-str.sh 
STR="Hello\nWorld"
echo $STR
[bash]§ sh test-str.sh 
Hello
World

これであなたの質問に答えられると思います。 (\nの代わりに改行文字がshで使用されている時点など、詳細を把握しようとはしていません)。

しかし、同じスクリプトをbashと実行したときの動作が異なり、代わりにHello\nWorldを出力することに気付きました。

[bash]§ bash test-str.sh
Hello\nWorld

次のようにして、bashで目的の出力を取得できました。

[bash]§ STR="Hello
> World"
[bash]§ echo "$STR"

$STRを囲む二重引用符に注意してください。これは、保存してbashスクリプトとして実行した場合も同じように動作します。

以下も望ましい出力を示します。

[bash]§ echo "Hello
> World"
0
Alexey