Bashのファイル記述子255について
Fri Nov 3 18:20:48 JST 2023 (modified: Fri Nov 3 18:41:07 JST 2023)
views: 3875, keywords:自作シェル, bash, 連載 この記事は最終更新日が1年以上前のものです。
連載「魅惑の自作シェルの世界」のための調べものをしていて、以前から気になってた「BashのFD255」について真面目に調べました。なんのことかというと、これのことです。
ls -l /proc/$$/fd
$ 0
合計 lrwx------ 1 ueda ueda 64 11月 3 13:55 0 -> /dev/pts/1
lrwx------ 1 ueda ueda 64 11月 3 13:55 1 -> /dev/pts/1
lrwx------ 1 ueda ueda 64 11月 3 13:55 2 -> /dev/pts/1
lrwx------ 1 ueda ueda 64 11月 3 13:55 255 -> /dev/pts/1 #これは何?
標準入出力のファイル記述子(FD)0, 1, 2番が端末につながっているのは分かりますが、255番がいるのはなんなのかと。
しらべた結果
このページにたどりつきました。全部書いてありました。読めば書いてあるんですが、「Bashがインタラクティブシェルとして使われているときに、標準エラー出力がリダイレクトされたときのユーザーとの通信用」とのことです。
実はこのページ、最初から255の謎を調べていたわけではなく、「端末とつながっているファイル記述子を、なんでもいいからひとつズボラに探す方法」を探していてついでに発見したものです。確かに255がそういうものなら、255は端末につながっているとして良さそうです。ユーザーが変なリダイレクトをしなければ、という話ですが。やるなよ!絶対やるなよ!
ということで変な操作をしてみる
シェルでexec 255>&-
を打つと255を閉じることができるので、実験してみましょう。
コマンドにフォアグラウンドを渡さない
まず、exec
の前に、次のようにps
を打ってみます。
ps au --forest
$ USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
・・・ueda 210157 0.0 0.0 12828 5440 pts/3 Ss 15:02 0:00 bash
ueda 218236 0.0 0.0 13716 3360 pts/3 R+ 18:11 0:00 \_ ps au --forest
・・・
ps
のSTATの項目に+
がつきますが、これはps
がフォアグラウンド(端末とむすびついている)という印です。
ここで、exec
して255を閉じてしまいます。
exec 255>&-
$ ls -l /proc/$$/fd
$ 0
合計 lrwx------ 1 ueda ueda 64 11月 3 13:55 0 -> /dev/pts/3
lrwx------ 1 ueda ueda 64 11月 3 13:55 1 -> /dev/pts/3
lrwx------ 1 ueda ueda 64 11月 3 13:55 2 -> /dev/pts/3
これで再びps
を実行すると・・・
ps au --forest
$
・・・USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
ueda 210157 0.0 0.0 12828 5440 pts/3 Ss+ 15:02 0:00 bash
ueda 218270 0.0 0.0 13716 3360 pts/3 R 18:13 0:00 \_ ps au --forest
・・・
というように、シェルのほうがフォアグラウンドのままになります。ちゃんとBashのコードを読んでいませんが、Bashが端末につながっているかどうかを255で確認しているのだと思います。
コマンドに画面を渡さない
上記の挙動は普通のコマンドだとあまり問題になりませんが、画面を占拠するようなコマンドがエラーを出すようになります。
top
$ bash: [210157: 1 (255)] tcsetattr: 不正なファイル記述子です
1]+ 停止 top
[vi
$ bash: [210157: 1 (255)] tcsetattr: 不正なファイル記述子です
2]+ 停止 vi
[jobs
$ 1]- 停止 top
[2]+ 停止 vi
[exit #たぶんexitすると消えてくれます。(ゾンビになってたらごめんなさい) $
Bashを固める
また、こういう遊びもできます(どうしてこうなるかは解析していません)。
stty tostop
$ exec 255&>-
$ (固まる)
試した環境
次のとおりです。
echo $BASH_VERSION
$ 5.1.16(1)-release
cat /etc/lsb-release
$ DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=22.04
DISTRIB_CODENAME=jammy
DISTRIB_DESCRIPTION="Ubuntu 22.04.3 LTS"
現場からは以上です。シェルを壊すのはたのしいです。