bashでコマンドの結果を格納して、それを行単位でloopで回そうとすると結構面倒で、間違いやすいので備忘録として書く。
結論
コマンドの結果は()に入れてarray variableにして、更にIFSをいじってやるのが一番確実(?)っぽい。
環境
bash-4.4$ tree /path/to/dir
/path/to/dir
├── foo\ bar
├── fuga
└── hoge
0 directories, 3 files
コード
sample.sh
# !/usr/bin/env bash
oldifs="${IFS}"
IFS=$'\n' # Internal Field Separatorをnew lineに限定
arr=( $( ls /path/to/dir ) ) # ()で囲んでarrayに。前行の処理により要素の区切りはnew lineのみになる
IFS="${oldifs}"
for elem in "${arr[@]}"; do # IFSで区切られた要素ごとではなく、配列の要素ごとにloopが回るように
echo "elem: " ${elem};
done
結果:
bash-4.4$ ./sample.sh
elem: foo bar
elem: fuga
elem: hoge
IFSをいじらなかったり、コマンドの出力結果を()で囲まないとスペース区切りに上手く対応できなかったり、逆に全部が一要素として認識されてループが上手く回らなかった。
補足
IFS=$'\n'でダラーを改行文字の前につけてるのは、\nをANSI-Cのエスケープシーケンスだとbashに認識させるため。
$ man 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
.
.
.
実験
bash-4.4$ echo '\n'
\n
bash-4.4$ echo $'\n'
bash-4.4$