web-dev-qa-db-ja.com

bashの変数から1行ずつ読み取るにはどうすればよいですか?

コマンドの複数行出力を含む変数があります。変数から行ごとに出力を読み取る最も効率的な方法は何ですか?

例えば:

jobs="$(jobs)"
if [ "$jobs" ]; then
    # read lines from $jobs
fi
53
Eugene Yarmash

Whileループをプロセス置換で使用できます。

while read -r line
do
    echo "$line"
done < <(jobs)

複数行の変数を読み取る最適な方法は、空白のIFS変数とprintf変数を後続の改行で設定することです。

# Printf '%s\n' "$var" is necessary because printf '%s' "$var" on a
# variable that doesn't end with a newline then the while loop will
# completely miss the last line of the variable.
while IFS= read -r line
do
   echo "$line"
done < <(printf '%s\n' "$var")

注: shellcheck sc2031 のように、サブシェルの作成を(微妙に)回避するために、パイプよりもプロセス置換の使用が推奨されます。

また、変数にjobsという名前を付けると、一般的なシェルコマンドの名前にもなるため、混乱を招く可能性があることに注意してください。

70
dogbane

問題:whileループを使用すると、サブシェルで実行され、すべての変数が失われます。解決策:forループを使用する

# change delimiter (IFS) to new line.
IFS_BAK=$IFS
IFS=$'\n'

for line in $variableWithSeveralLines; do
 echo "$line"

 # return IFS back if you need to split new line by spaces:
 IFS=$IFS_BAK
 IFS_BAK=
 lineConvertedToArraySplittedBySpaces=( $line )
 echo "{lineConvertedToArraySplittedBySpaces[0]}"
 # return IFS back to newline for "for" loop
 IFS_BAK=$IFS
 IFS=$'\n'

done 

# return delimiter to previous value
IFS=$IFS_BAK
IFS_BAK=
16
Dima
jobs="$(jobs)"
while IFS= read
do
    echo $REPLY
done <<< "$jobs"

参照:

11
l0b0

最近のbashバージョンでは、mapfileまたはreadarrayを使用して、コマンド出力を配列に効率的に読み取ります

$ readarray test < <(ls -ltrR)
$ echo ${#test[@]}
6305

免責事項:恐ろしい例ですが、自分でlsよりも使用するコマンドを多用することができます

10
sehe

<<<を使用して、改行で区切られたデータを含む変数から単純に読み取ることができます。

while read -r line
do 
  echo "A line of input: $line"
done <<<"$lines"
0