bash:変数の最初の行を変数に割り当てる


11

複数行の変数があり、その変数の最初の行だけが必要です。次のスクリプトは問題を示しています。

#!/bin/bash

STRINGTEST="Onlygetthefirstline
butnotthesecond
orthethird"

echo "  Take the first line and send to standard output:"
echo ${STRINGTEST%%$'\n'*}
#   Output is as follows:
# Onlygetthefirstline

echo "  Set the value of the variable to the first line of the variable:"
STRINGTEST=${STRINGTEST%%$'\n'*}

echo "  Send the modified variable to standard output:"
echo $STRINGTEST
#   Output is as follows:
# Onlygetthefirstline butnotthesecond orthethird

質問:コマンドの${STRINGTEST%%$'\n'*}後に配置すると最初の行を返すechoのに、割り当て後に配置すると改行をスペースに置き換えるのはなぜですか?


1
再現できません。期待どおりに動作します。
ペケ2015年

1
2.05b、3.1、3.2、4.0、4.1、4.2、4.3のいずれでも再現できません。$'...'bashの代わりにサポートしていないシェルで実行しようとすると、ユーザーエラーのように聞こえます。
ステファンChazelas

回答:


8

多分あなたがしたいことをアーカイブする他の方法がありますが、これはうまくいきます

#!/bin/bash

STRINGTEST="
Onlygetthefirstline
butnotthesecond
orthethird
"

STRINGTEST=(${STRINGTEST[@]})
echo "${STRINGTEST[0]}"

これは、行に$STRINGTEST空白やワイルドカードが含まれていないことを前提としています。また、空の行(その変数の最初の行など)は無視されることに注意してください。
ステファンChazelas

3
また、を使用STRINGTEST=(${STRINGTEST[@]})することはほとんど意味がなくSTRINGTEST=($STRINGTEST)STRINGTEST以前はスカラー変数(配列ではない)として定義されていたのと同じであることにも注意してください。
ステファンChazelas

10

最も効率的ではないかもしれませんが、ライナーが1つ...

firstLine=`echo "${multiLineVariable}" | head -1`

2
わかりやすく簡潔にするために、これを気に入っています。
ピーター-モニカの復活2017年

これはfirstLine=`echo "${test_var}" | sed -n 1p:あなたが使用する理由はなく、(例えば、それはあなたが同時に回線に交換を行うことができることを意味sedを持っている場合も動作しますecho "${test_var}" | sed -nE '1 s/# *(.*)/\1/p'
robenkleene

7

そのコードは、2.05bと4.3の間で試したbashのすべてのバージョンで機能します。おそらく$'...'、引用の形式をサポートしていない別のシェルでそのスクリプトを実行しようとした可能性があります。

その$'...'構文は標準ではありませんsh構文(まだ)だけで(2015年5月22日と私の知る限りのような)サポートksh93(それは元の場所)、 、zshbash最近のバージョンmkshshのFreeBSDのか、最近のバージョン

私の賭けは、あなたがそのスクリプトを実行しようとしたということでしょうsh代わりにbash、あなたshのバージョンに基づいていますashpdkshyashまたはksh88まだそれをサポートしていないこと。

そのコードをPOSIX 2008互換にする場合は、次のように記述する必要があります。

STRINGTEST="Onlygetthefirstline
butnotthesecond
orthethird"

NL='
'
STRINGTEST=${STRINGTEST%%"$NL"*}
printf '%s\n' "$STRINGTEST"

次に、のようなPOSIX準拠のシェルbashや、のようなよりスリムで高速なシェルによって解釈させることができますsh

(そして、リストコンテキストで引用符で囲まれていない変数を残すことは、ボーンのようなシェルでは非常に特別な意味があることを覚えておいてください)。


または、古いバージョンのbashである可能性もあります。2.03で動作を再現できました。
Gilles「SO-邪悪なことをやめ

@ Gilles、bash-2.03(16年前にリリースされた)を含む最後にサポートされたOSは、おそらく3年以上前にEOLになったSolaris 8でした。その仮説はかなりありそうにないようです。
ステファンChazelas

1

これは私にとってはうまくいきます:

STRINGTEST="Some Text 1
Some Text 2
Some Text 3"

readarray -t lines < <(echo "$STRINGTEST")
echo "${lines[0]}"

そして、それは空白行にも機能します:

STRINGTEST="
Some Text 1
Some Text 2
Some Text 3"

readarray -t lines < <(echo "$STRINGTEST")
echo "${lines[0]}"

プロセスの置換を起動するのが面倒readな場合は、単純な変数に(readarrayプラスのインデックス付けの代わりに)一度だけでもよいでしょう。
ピーター-モニカの復活2017年

0

Bash組み込みreadとhere-stringの場合:

#!/usr/bin/env bash

STRINGTEST="
Some Text 1
Some Text 2
Some Text 3"


IFS=$'\n' read -r STRINGTEST <<<"$STRINGTEST"

POSIXパラメータ拡張の使用:

#!/usr/bin/env sh

STRINGTEST="
Some Text 1
Some Text 2
Some Text 3"

# Disables globing
set -f

# Field separator is newline only
IFS="
"

# No quotes, split lines as arguments because of IFS
set -- $STRINGTEST

# First argument is first line
STRINGTEST="$1"
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.