先に簡単に方法をまとめておきます
'script.sh > /dev/null 2>&1' とやっても、画面に出力させる
echo "Hello tty world" >/dev/tty
'yes | script.sh' とやっても、自動入力させない
line=$(head -n 1 < /dev/tty) echo $line
以下、調べる動機とか
動機
実は以下の記事にコメントがついたのを機にちょっと調べたのでした。
シェルスクリプト(とよくあるコマンド)でexpectのように自動応答させる - 日々量産
お話はSSH接続してなんか情報をとってみようとするところから始まります。
ssh hoge@localhost ls -l
すると、パスワード認証にかかった場合、以下の画面になり、パスワードを入力する必要があります。
この入力は標準入力に違いない!と思い、echoで自動応答させようとしてみます。(あまり頭のよくない発想です。)
echo secretkey | ssh hoge@localhost ls -l
しかし、同じ画面になります。
どうやら、標準入力ではないようです。
ではこの挙動をどうやるのか。ちょっと調べてみました。
結果から言うと、ttyからの入力を受け付けるようになってるようです。
ttyっていうのは、簡単に言えば「今見ているコンソール」のことです。
ttyへの入力ができるのなら、ttyからの出力も制御してると思い、
エラー出力と標準出力を/dev/nullへリダイレクトするようにしてみました。
ssh -v hoge@localhost > /dev/null 2>&1 # -v をつけると内部の動作がトレースログのように出力されますが、今回は/dev/nullにリダイレクトされるので、これは出力されません。
出力を/dev/nullに向けているはずなのに、画面は先ほどのようになります。
これを利用すれば、鬱陶しいスクリプトが書けそうですね。
シェルスクリプトでやってみる
シェル
$ sh --version GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu) Copyright (C) 2009 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later http://gnu.org/licenses/gpl.html
実験コード(msg.sh)
#!/bin/sh echo "Hello stdout world" echo "Hello stderr world" >&2 # ttyへ出力 echo "Hello tty world" >/dev/tty echo -n "input here: " read line; echo "[input]: $line"; echo -n "input here: " # ttyから入力(1行) line=$(head -n 1 < /dev/tty) echo "[input]: $line";
普通に使う
$ sh msg.sh
Hello stdout world
Hello stderr world
Hello tty world
input here: aaa
[input]: aaa
input here: bbb
[input]: bbb
エラー出力・標準出力を捨てる
$ sh msg.sh >/dev/null 2>&1
Hello tty world
aaa
bbb
(input here:とか表示されてないので味気ない...)
自動入力
$ yes aaa | sh msg.sh
Hello stdout world
Hello stderr world
input here: [input]: aaa
input here: bbb
[input]: bbb
うまく動いてます。