制御端末の実際の名前を取得するには?

制御端末の実際の名前を取得するには?

制御端末の実際の名前(存在する場合、そうでない場合はエラーが発生した場合)をパス名としてどのように取得しますか?

「本名」とは、他/dev/ttyの任意のプロセスがそれを使用して同じ端末を参照できるという意味ではありません。可能であれば、単純なシェルコード(以下の例のように)で答えを好み、そうでなければC関数で答えることを好みます。

これは、標準入力がリダイレクトされても機能する必要があるため、ttyユーティリティを使用できません。この場合、標準入力に接続されている端末のファイル名のみが印刷されるnot a ttyため、エラーが表示されます。tty

Linuxでは、次のものを使用できます。

echo "/dev/`ps -p $$ -o tty | tail -n 1`"

しかし、POSIXによると、これは移植性がありません。端末名の形式が指定されていません。

C関数の場合はctermid (NULL)returnを使用します/dev/tty。ここでは役に立ちません。

メモ:zsh文書によると、次のことができるはずです。

zsh -c 'echo $TTY'

ただし、現在(バージョン5.0.7)stdinとstdoutの両方がリダイレクトされると失敗します。

$ zsh -c 'echo $TTY > /dev/tty' < /dev/null
/dev/pts/9
$ zsh -c 'echo $TTY > /dev/tty' < /dev/null > /dev/null
/dev/tty

答え1

「制御端末」とも呼ばれます。 cttyは「とは異なります。これプロセスが対話する端末です。」

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)はttyname(fileno(stdin))cと同じstdinに接続されている端末パスを印刷し、代わりにです readlink /proc/self/fd/0


無条件の「/dev/tty」の動作についてあまり重要ではない考え方:仕様では、単に「現在のパス」ではなく、「パス名として使用されたときに現在の制御端末を参照」するctermidによって返される文字列があると言います。名前は「control端末」です。 「/dev/tty」は、制御端末ではなく、同じプロセスが開かれたときにのみ制御端末を参照するものと解釈できるため(3)違反はありません。 「ターミナルは最大1つのセッションのCTYにすることができます。」ルール[7]。

別の結果は、制御端末がなくてもctermidが失敗しないことです。仕様では、これらのエラーを受け入れます。[8] - だから私は後続のopen(3)が失敗するまでctty'lessであることに気づいていません。これはまた、仕様にopen(3)呼び出しが成功を保証しないことを示しているので、大丈夫です。

答え2

POSIX仕様は実際に賭けをヘッジします。制御端子関連性があり、次のように定義されます。

  • 制御端子
    • 端末用のいくつかの特殊ファイルのうち、どのファイルを関連付けることができるかについての質問は、POSIX.1では解決されていません。パス名は、/dev/ttyプロセスに関連付けられた制御端末の同義語です。

これは定義リストにあります。それがすべてです。しかし、汎用端末インターフェース、そして次のような言葉があります。

  • 端末は制御端末としてプロセスに属することができる。制御端末とのセッションの各プロセスは同じ制御端末を有する。端末は、最大1つのセッションを制御するターミナルにすることができます。セッションの制御エンドポイントは、実装定義の方法でセッションリーダによって割り当てられます。セッションリーダーに制御端末がなく、セッションにまだ関連付けられていない端末装置ファイルがO_NOCTTYオプション(open()を参照)を使用せずに開かれる場合、その端末がセッションの制御端末になるかどうかは実装です。定義されたリーダー。

  • fork() 関数呼び出し中、制御端末は子プロセスによって継承されます。プロセスがこの機能を使用して新しいセッションを作成すると、制御端末には端末が残っているsetsid()ため、端末を保持していた以前のセッションの他のプロセスを放棄します。システムの制御端末に関連した最後のファイル記述子が(現在のセッションにあるかどうかにかかわらず)閉じられると、その端末を制御端末として使用するすべてのプロセスが制御端末を所有していないかどうかは指定されません。セッションリーダーがこのように制御端末を放棄した後に制御端末を再取得するかどうか、および方法は指定されていません。他のプロセスがそのプロセスを開け続けると、そのプロセスは、制御端末に関連するすべてのファイル記述子を閉じることによって、制御端末を放棄しない。

まだたくさん残ってる指定されていない-正直、その言葉が正しいと思います。ターミナルは主なユーザーインターフェイスですが、場合によっては実際のハードウェアやプリンタの種類などの他のさまざまな要素ですが、ほとんどの場合実際には何もありません。まるでエミュレータxtermだけです。これを指定するのは難しいです。そして、端末がUnixよりも多くのことをしているので、とにかくUnixに多くの利点があるとは思いません。

psそれにもかかわらず、POSIXはcttyの仕組みについてもかなり不確実です。

スイッチがあります-a

  • 端末に関連するすべてのプロセスに関する情報を書き込みます。実装では、このリストからセッションリーダーを省略できます。

途方もない。支部会長の指導者可能省略しています。これはあまり役に立ちません。

そして-t

  • 用語リストで提供される端末に関連するプロセスに関する情報を作成します。アプリケーションは、用語リストがカンマ区切り<blank>リスト形式の単一引数であることを確認する必要があります。端末識別子は次の場所になければなりません。実装定義滞在。

...また失望ですね。ただし、XSI システムについては引き続き説明します。

  • XSI準拠のシステムでは、デバイスのファイル名(例tty04:)またはデバイスのファイル名がtty次に始まる場合は、2つの形式のいずれかで指定する必要があります。tty (たとえば、04

これは良いですが、行く道ではありません。 XSIシステムにもスイッチがあります-d

  • セッションリーダーを除くすべてのプロセスに情報を書き込みます。

...少なくともそれは明らかです。形式文字列を使用して出力スイッチを指定すること-oもできますが、指摘した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に添付された記述子は次のとおりです。

tty <&2

...または同様です。

関連情報