Bashのファイル記述子255について
Fri Nov 3 18:20:48 JST 2023 (modified: Fri Nov 3 18:41:07 JST 2023)
views: 4718, keywords:自作シェル, bash, 連載 この記事は最終更新日が2年以上前のものです。
連載「魅惑の自作シェルの世界」のための調べものをしていて、以前から気になってた「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"現場からは以上です。シェルを壊すのはたのしいです。
ノート
Tweet