回答:
解決策は$'string'
、たとえばを使用することです。
$ STR=$'Hello\nWorld'
$ echo "$STR" # quotes are required here!
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.
STR=$"Hello\nWorld"
単に出力しHello\nWorld
ます。
H="Hello"; W="World"; STR="${H}"$'\n'"${W}"; echo "${STR}"
「Hello」と「World」を別々の行にエコーします
エコーは非常に90年代であり、非常に危険に満ちているので、その使用は4GB以上のコアダンプをもたらすはずです。真剣に、エコーの問題は、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
今すぐ使ってください、決して振り返ってはいけません。
$'string'
クリーンだと思います。
$'foo'
構文は文句を言うでしょう2013年、多くの貝殻の有効なPOSIX構文ではありません。
BAR=$(printf "hello\nworld\n")
私の末尾の\ nを出力しません
$()
としてPOSIXで指定されています。
問題はシェルにありません。問題は実際にはecho
コマンド自体にあり、変数の補間を囲む二重引用符がありません。使用してみることができますがecho -e
、すべてのプラットフォームでサポートされているわけではなくprintf
、移植性のために理由の1つが推奨されています。
改行をシェルスクリプトに直接挿入して(スクリプトが作成中の場合)、次のようにすることもできます...
#!/bin/sh
echo "Hello
World"
#EOF
または同等に
#!/bin/sh
string="Hello
World"
echo "$string" # note double quotes!
-e
旗はエレガントでわかりやすいと思います
bash$ STR="Hello\nWorld"
bash$ echo -e $STR
Hello
World
文字列が別のコマンドの出力である場合、引用符を使用します
indexes_diff=$(git diff index.yaml)
echo "$indexes_diff"
echo
。
echo -e
移植性の問題で悪名高い。これは現在、POSIX以前よりもワイルドウエストの状況ではありませんが、優先する理由はまだありませんecho -e
。stackoverflow.com/questions/11530203/…
唯一の簡単な方法は、実際に変数に新しい行を入力することです。
$ STR='new
line'
$ printf '%s' "$STR"
new
line
はい、それはEnterコードの必要な場所に書き込むことを意味します。
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
一部のシェルでは、シーケンス$'は特別なシェル拡張です。ksh93、bash、zshで動作することが知られています:
$ STR=$'new\nline'
もちろん、より複雑なソリューションも可能です:
$ echo '6e65770a6c696e650a' | xxd -p -r
new
line
または
$ echo "new line" | sed 's/ \+/\n/g'
new
line
私のシステム(Ubuntu 17.10)では、コマンドライン(into 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"
改行だけを必要とし、インデントを解除する複数行のコードを軽視するうるさいものは、次のようになります。
IFS="$(printf '\nx')"
IFS="${IFS%x}"
Bash(および他のシェル)はコマンド置換後にすべての末尾の改行をむちゃくちゃにするので、printf
文字列を改行以外の文字で終了し、後で削除する必要があります。これも簡単にワンライナーになります。
IFS="$(printf '\nx')" IFS="${IFS%x}"
私はこれが1つのアクションではなく2つのアクションであることを知っていますが、私のインデントと移植性のOCDは現在安定しています:)私は元々、改行のみの分離された出力を分割できるようにこれを開発
\r
し、終了文字として使用する変更を使用してしまいました。これにより、末尾がで終わるdos出力でも、改行の分割が機能します\r\n
。IFS="$(printf '\n\r')"
ここにあるオプションのどれにも満足していませんでした。これは私のために働いたものです。
str=$(printf "%s" "first line")
str=$(printf "$str\n%s" "another line")
str=$(printf "$str\n%s" "and another line")
str=$(printf '%s\n' "first line" "another line" "and another line")
(シェルはコマンドの置換から最終的な改行を削除する(またはしない)ので便利です)。ここのいくつかの回答はすでにprintf
さまざまな形で宣伝されているので、これが別の回答として価値を追加するかどうかはわかりません。
printf '%s\n' "first line" \
(改行、インデント)'second line'
などを好みますprintf -v str
。サブシェルを生成せずに変数に割り当てる方法も参照してください。