制御端末の実際の名前(存在する場合はエラー)をパス名として取得するにはどうすればよいですか?
「実際の名前」とは、/dev/tty
ではなく、他の任意のプロセスが同じ端末を参照するために使用できないことを意味します。可能な場合は、単純なシェルコード(以下の例のような)として、そうでない場合はC関数として、答えを好みます。
これは、標準入力がリダイレクトされる場合でも機能する必要があるため、tty
ユーティリティを使用できないことに注意してください。このような場合、tty
はファイル名を出力するだけなので、not a tty
エラーが発生します。標準入力に接続された端末の。
Linuxでは、以下を使用できます。
echo "/dev/`ps -p $$ -o tty | tail -n 1`"
ただし、POSIXによると、これは移植可能ではありません 端末名の形式は指定されていません 。
C関数に関しては、ctermid (NULL)
は/dev/tty
を返しますが、ここでは役に立ちません。
注:zsh
のドキュメントによれば、できるはずです
zsh -c 'echo $TTY'
しかし、現在(バージョン5.0.7)は、標準入力と標準出力の両方がリダイレクトされると失敗します。
$ zsh -c 'echo $TTY > /dev/tty' < /dev/null
/dev/pts/9
$ zsh -c 'echo $TTY > /dev/tty' < /dev/null > /dev/null
/dev/tty
「管理端末」とも呼ばれます。 cttyは、「theプロセスが対話している端末」とは異なります。
Cttyのパスを取得する標準的な方法はctermid(3)です。これを呼び出すと、 リリース10以降のfreebsdでは実際のパスが検索されます [1]、古いfreebsdおよび glibc実装 [2]は無条件に "/ dev/ttyを返します「]。
linux procps 3.2.8パッケージのps(1) / proc/*/statの数値エントリを読み取る [3]、次に パス名を差し引く部分的に推測 [4、5] システムサポートの欠如 [6]による。
ただし、cttyに厳密に関心がなく、stdioに関連付けられている端末がある場合、tty(1)は、stdinに接続された端末パスを出力します。これは、cのttyname(fileno(stdin))
と同じです。代わりにreadlink /proc/self/fd/0
。
無条件の「/ dev/tty」の動作に関するそれほど重要ではない考え:仕様は、単純な「現在のパス名である」ではなく、単にctermidによって返された文字列を「パス名として使用する場合、現在の制御端末を参照する」と言います制御端末」。 "/ dev/tty"は制御端末ではなく、同じプロセスでopen(3)を実行した場合にのみ制御端末を参照すると解釈される場合があります。したがって、 "端末は多くても1つのセッションでcttyになる可能性があります"ルール [7]に違反していません。
別の結果として、制御端末がない場合でも、ctermidは失敗しません- このような失敗はspecで許可されています [8]-したがって、失敗するまでcttyの不足に気づくことができます後続のopen(3)。これは、仕様でopen(3)の呼び出しが成功することを保証するものではないため、問題ありません。
POSIX仕様では、 Controlling Terminal が関係する場合、その定義を実際にヘッジしています。
/dev/tty
_は、プロセスに関連付けられた制御端末の同義語です。それは定義リストにあります-それがすべてです。しかし General Terminal Interface では、さらにいくつかが言われています:
端末は、その制御端末としてプロセスに属する場合があります。制御端末を持つセッションの各プロセスには、同じ制御端末があります。端末は最大で1つのセッションの制御端末である場合があります。セッションの制御端末は、実装で定義された方法でセッションリーダーによって割り当てられます。セッションリーダーに制御端末がなく、O_NOCTTYオプションを使用せずにセッションに関連付けられていない端末デバイスファイルを開く場合(open()を参照)、端末がセッションの制御端末になるかどうかは実装定義です盟主。
制御端末は、fork()関数呼び出し中に子プロセスによって継承されます。プロセスは、setsid()
関数を使用して新しいセッションを作成するときに、制御端末を放棄します。制御端末としてこの端末を持っていた、古いセッションに残っている他のプロセスは、引き続きそれを持っています。制御端末に関連付けられているシステム内の最後のファイル記述子(現在のセッションにあるかどうかに関係なく)を閉じると、その端末を制御端末として使用していたすべてのプロセスが制御端末を停止するかどうかは不明です。この方法で制御端末が放棄された後、セッションリーダーが制御端末を再取得できるかどうか、およびその方法は指定されていません。他のプロセスが制御端末を開いたままにしている場合、プロセスは、制御端末に関連付けられているファイル記述子をすべて閉じるだけでは、制御端末を放棄しません。
unspecifiedがたくさん残っています-正直なところ、それは理にかなっていると思います。端末は主要なユーザーインターフェイスですが、実際のハードウェアやプリンターのような場合もありますが、多くの場合、実際にはまったく何もありません。xterm
は単なるエミュレータ。ここで具体的に説明するのは困難です。とにかく、Unixよりも端末の機能が多いため、Unixの利益に大きく影響するとは思いません。
とにかく、POSIXは、cttyが関係している場合にps
がどのように動作するかについてもかなり疑わしいです。
_-a
_スイッチがあります:
すごい。セッションリーダーは省略できます。それはあまり役に立ちません。
そして_-t
_:
<blank>
_またはコンマ区切りリストの形式の単一の引数であることを確認する必要があります。端末識別子はimplementation-defined形式で指定します。...これは別の失望です。しかし、XSIシステムについて次のように言っています。
tty04
_)またはデバイスのファイル名がtty
で始まる場合は、tty
(たとえば、_04
_)。それは少し良いですが、道ではありません。また、XSIシステムには_-d
_スイッチがあります。
...それは少なくとも明確です。 _-o
_ utputスイッチは、tty
形式の文字列でも指定できますが、既に説明したように、その出力形式は実装定義です。それでも、それはそれが得られるほど良いと思います。私は-多くの作業で-上記のスイッチを他のユーティリティと組み合わせて使用すると、かなり良い球場が得られると思います。正直なところ、それがいつ、どのように機能しなくなるかはわかりません。また、そのような状況を想像することもできませんでした。しかし、fuser
とfind
を追加すると、パスを確認できると思います。
_exec 2<>/dev/null
ctty=$(sh -c 'ps -p "$$" -o tty=' <&2)
sid=$(sh -c 'ps -Ao pid= -o tty=|
grep '"$ctty$"' |
grep -Fv "$(ps -do pid=)"' <&2)
find / -type c -name "*${ctty##*/}*" \
-exec fuser -uv {} \; 2>&1 |
grep ".*$ctty.*${sid%%"$ctty"*}"
_
_/dev/null
_の要素は、cttyに接続されている0、1、2のいずれの検索サブシェルもない場合に機能することを示しているだけです。とにかく、それは印刷します:
_/dev/pts/3: mikeserv 3342 F.... (mikeserv)zsh
_
今、上記は私のマシン上の完全なパスを取得し、ほとんどの場合、ほとんどの人にとってそうなると思います。それが失敗することも想像できます。これは、大まかなヒューリスティックです。
これは他の多くの理由で失敗する可能性がありますが、セッションリーダーがすべての記述子をcttyに放棄し、仕様が許す限りsidを維持できるシステムを使用している場合、これは間違いなく役に立ちません。とはいえ、ほとんどの場合、これはかなり良い見積もりになると思います。
もちろん、cttyにany記述子が接続されている場合に行う最も簡単なことは...
_tty <&2
_
...または類似。