シェルスクリプトのwhile..do..doneループのお勉強

2020-07-23

KDE neonを使おう

t f B! P L
Linux/UNIX: Bash Read a File Line By Line - nixCraft
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行にして渡されてしまいます。

ブログ検索 by Blogger

Translate

最近のコメント

Created by Calendar Gadget

QooQ