While loop - Linux Shell Scripting Tutorial - A Beginner's handbook
bash read コマンドを利用する場合には、基本的に -r オプションを使うべき。 - Qiita
readするときはIFS=を付けておくとstrictな感じで気持ちが良い - Qiita
これらのページがとても参考になりました。
readコマンドで1行ずつ読み込む
#!/bin/bash
C=0
while read S
do
echo line$((++C)): ${S}
done << EOS
hello
world
EOS
exam.shというファイルにこれを保存しました。 ヒアドキュメントでソースとなるテキストを渡しています。
pq@linuxBean:~/tmp$ bash ./exam.sh
line1: hello
line2: world
1行ずつ出力されています。\をそのまま文字として出力するにはrオプションをつける
#!/bin/bash
C=0
while read S
do
echo line$((++C)): ${S}
done << EOS
hello\nworld
EOS
rオプションをつけないと\が無視されてnだけ出力されます。pq@linuxBean:~/tmp$ bash ./exam.sh
line1: hellonworld
こんな出力のされ方は困りますね。 #!/bin/bash
C=0
while read -r S
do
echo line$((++C)): ${S}
done << EOS
hello\nworld
EOS
readにrオプションをつけると\nのまま出力してくれます。pq@linuxBean:~/tmp$ bash ./exam.sh
line1: hello\nworld
\nは出力されますが改行としては機能していません。行をつなげる\はrオプションをつけてもつけなくても機能する
#!/bin/bash
C=0
while read -r S
do
echo line$((++C)): ${S}
done << EOS
hello \
world
EOS
この\はrオプションをつけてもつけてなくても同じように1行で出力されます。pq@linuxBean:~/tmp$ bash ./exam.sh
line1: hello world
ということでreadではrオプションをつけることにします。IFS(Internal Fieled Separator)の変更
#!/bin/bash
C=0
while read -r X Y
do
echo line$((++C)): "<${X}><${Y}>"
done << EOS
hello world
EOS
IFSはフィールド内の区切りで、デフォルトではスペース、タブ、改行がIFSになっているので、helloとworldがそれぞれXとYに代入されます。pq@linuxBean:~/tmp$ bash ./exam.sh
line1: <hello><world>
IFSを消去する
#!/bin/bash
C=0
while IFS= read -r X Y
do
echo line$((++C)): "<${X}><${Y}>"
done << EOS
hello world
EOS
IFS=でIFSに何も代入せずにIFSを消去します。pq@linuxBean:~/tmp$ bash ./exam.sh
line1: <hello world><>
区切り文字がないので、すべてがXに代入されています。1行を分割して空白以外で区切られたテキストを複数の変数で受け取りたいときはIFSの変更が必要になりますね。
連続する半角スペースをそのまま表示する方法
これはechoの仕様も絡んできます。#!/bin/bash
C=0
while read -r S
do
echo line$((++C)): $S
done << EOS
hello world
EOS
helloとworldの前に2つの半角スペースが入っていますが出力では1つの半角スペースにされています。pq@linuxBean:~/tmp$ bash ./exam.sh
line1: hello world
連続する半角スペースをそのまま出力するにはダブルクォーテーションで囲みます。
#!/bin/bash
C=0
while read -r S"
do
echo line$((++C)): "$S"
done << EOS
hello world
EOS
この方法では行頭のスペースはまだ1つにされてしまいます。pq@linuxBean:~/tmp$ bash ./exam.sh
line1: hello world
IFSを消去すると行頭のスペースも1つにされません。#!/bin/bash
C=0
while IFS= read -r S
do
echo line$((++C)): "$S"
done << EOS
hello world
EOS
pq@linuxBean:~/tmp$ bash ./exam.sh
line1: hello world
これで入力したとおりに出力できました。
while..do..doneにデータを渡す方法
入力と出力 | UNIX & Linux コマンド・シェルスクリプト リファレンス
この入力と出力の解説を参考にします。
ファイルパスを渡す
<でファイルディスクリプタ 0番(標準入力)へのリダイレクションでファイルの内容を渡します。
#!/bin/bash
C=0
while read -r S
do
echo line$((++C)): $S
done < /etc/resolv.conf
pq@linuxBean:~/tmp$ bash ./exam.sh
line1: # Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
line2: # DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
line3: nameserver 127.0.1.1
コマンドの出力結果を渡す
<(コマンド)でコマンドの出力結果をファイルとして扱えます。
この機能をプロセス置換(コマンド置換)といいます。
#!/bin/bash
C=0
while read -r S
do
echo line$((++C)): "$S"
done < <(ps au)
スペースを1つにされると列がずれてしまうので出力でダブルクォーテーションを使っています。
pq@linuxBean:~/tmp$ bash ./exam.sh
line1: USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
line2: root 751 0.0 0.0 4644 836 tty2 Ss+ 12:35 0:00 /sbin/getty -8 38400 tty2
line3: root 855 0.1 1.5 92068 32272 tty7 Ss+ 12:35 0:48 /usr/bin/X :0 vt07 -nolisten tcp
line4: root 1439 0.0 0.0 4644 828 tty1 Ss+ 12:35 0:00 /sbin/getty -8 38400 tty1
line5: pq 13955 0.0 0.0 5284 1296 pts/0 S+ 22:39 0:00 bash ./exam.sh
line6: pq 13956 0.0 0.0 5288 564 pts/0 S+ 22:39 0:00 bash ./exam.sh
line7: pq 13957 0.0 0.0 5212 1168 pts/0 R+ 22:39 0:00 ps au
line8: pq 23107 0.0 0.1 6900 3100 pts/0 Ss 18:18 0:00 bash
line9: pq 31860 0.0 0.1 6900 3104 pts/1 Ss+ 14:17 0:00 bash
ヒアドキュメントで複数行の文字列を渡す
<< EOS 複数行テキスト EOSで文字列を渡します。
#!/bin/bash
C=0
while read S
do
echo line$((++C)): ${S}
done << EOS
hello
world
EOS
ヒアドキュメントについてはbashのヒアドキュメントを活用する - Qiitaを参考にして先頭行と最終行の文字はEOSとしています。pq@linuxBean:~/tmp$ bash ./exam.sh
line1: hello
line2: world
ヒアストリングで文字列を渡す
<<<で文字列を渡します。
#!/bin/bash
C=0
while read -r S
do
echo line$((++C)): $S
done <<< "hello world"
複数行の文字列は渡せませんが、$(コマンド)でコマンドが渡せます。
#!/bin/bash
C=0
while read -r S
do
echo line$((++C)): "$S"
done <<< "$(ps au)"
これで< <(ps au)と同じ結果が得られます。
<<< $(ps au)のようにダブルクォーテーションを付けないと1行にして渡されてしまいます。
0 件のコメント:
コメントを投稿