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$