シェルスクリプトで、標準入力を開きっぱなしにしていると、標準入力を取得するところで停止してしまい次のコードへ進まない。標準入力を閉じれば進むが、閉じたくない。
readを使用すると、改行コードなどがない場合にデータが取れない。
そんな状況になったので、解決方法を探してみた。
テスト実行
入力待ち1
nc -l 6666 | while read -r line ; do cat - ; echo next ;done
入力待ち2
nc -l 6666 | while read -r line ; do echo "${line}" test ;done
データ送信
curl 'http://127.0.0.1:6666' --data 'aaa&bbb'
結果1
Host: 127.0.0.1:6666
User-Agent: curl/7.51.0
Accept: */*
Content-Length: 7
Content-Type: application/x-www-form-urlencoded
aaa&bbb
結果2
test/ HTTP/1.1
test 127.0.0.1:6666
testAgent: curl/7.51.0
testt: */*
testnt-Length: 7
testnt-Type: application/x-www-form-urlencoded
test
解決案
標準入力を閉じれば、全部のデータが取れて、次のコードへ進める。
しかし閉じたくないのであれば、標準入力を差し替えて止めれば、あるいは。。
それならば、下記のことをすればできるはず。
- 標準入力を一旦逃して、今ある分を
cat
で標準入力させる -
cat
をkill
する - 標準入力を取得すると、最初に
cat
されたものが取得でき、入力が閉じているので、次のコードへ進む - 最初に逃した標準入力を標準入力に戻す
コード
in.sh
#!/bin/bash
while read -r line
do
exec 5>&0 < <(cat -) 2>/dev/null
while true
do
pid=$(ps -o pid --ppid $! --no-header)
[ "${pid}" ] || continue
kill ${pid}
break
done
data+=$(cat)
exec <&5
echo "##### output #####"
echo "${data}"
echo "##### next #####"
done
echo "###### END ########"
実行と結果
入力待ち
$ nc -l 6666 | bash in.sh
データ送信
curl 'http://127.0.0.1:6666' --data 'aaa&bbb'
結果
aa.sh: 5 行: 1266 Terminated cat -
##### output #####
Host: 127.0.0.1:6666
User-Agent: curl/7.51.0
Accept: */*
Content-Length: 7
Content-Type: application/x-www-form-urlencoded
aaa&bbb
##### next #####
なんか動いた! が、なんだこれw
一行目が抜けているけど、これは、最初のexecの直前で別途取ればいいだけ。
あと、一行目のエラーメッセージの消し方は分からなかった。
。。。力技すぎるので、正規のやり方や良いやり方を知ってる方がいたら、教えてください。
この解決策については、ググり方が分からない。。