ファイル記述子255はBashで何をしており、使用できますか?

ファイル記述子255はBashで何をしており、使用できますか?

わかりました。ファイル記述子(またはファイルハンドラ)はいファイルIOテクノロジLinuxシステムで。

また、すべてのプロセスには、0から3までの記述子を持つファイルで表される3つの標準ストリーム(つまりstdin、stdout、およびstderr)があることもわかっています。

しかし、私が確認したすべてのプロセスには、lsof -p <pid>読み取り権限を持つ追加のファイル記述子があることがわかりました。255

~からこの回答、私はこの機能が次に特定であることを学びました。バッシュシェルただし、答えや引用されたソースのいずれも、実際にこのファイル記述子が使用される用途を説明していません。

私の質問:

  1. 255 ファイル記述子の用途は?
  2. 私のBashスクリプトでこれを使用できますか?それとも手動で使用/操作してはならない内部作業メカニズムですか?

答え1

質問の最後の部分は次のとおりです。

使えますか?

からman bash

9より大きいファイル記述子を使用するリダイレクトは、シェルで内部的に使用されるファイル記述子と競合する可能性があるため、慎重に使用する必要があります。

したがって、その番号で新しいファイル記述子を生成するという意味であれば、答えは「いいえ」です。

asを使用して「対応するfdに書き込む」を意味する場合:

$ echo hello >/dev/fd/255"

または、以下でお読みください。

$ read a </dev/fd/255
abc
$ echo "$a"
abc

答えは「はい」です。
しかし、おそらく/dev/ttyそれを使用してtty

ファイル記述子255は何に使用されますか?

/dev/stdoutfd 1()とfd 0(/dev/stdin)がブロックされている場合は、ttyへの代替接続として機能します。

詳しくは

異なるシェルでは異なる数字を使用できます(例:zshでは10)。

$ zsh
mail% ls -l /proc/self/fd /proc/$$/fd/* &
[1] 3345
mail% lrwx------ 1 isaac isaac 64 Oct 14 09:46 /proc/3250/fd/0 -> /dev/pts/2
lrwx------ 1 isaac isaac 64 Oct 14 09:50 /proc/3250/fd/1 -> /dev/pts/2
lrwx------ 1 isaac isaac 64 Oct 14 09:50 /proc/3250/fd/10 -> /dev/pts/2
lrwx------ 1 isaac isaac 64 Oct 14 09:50 /proc/3250/fd/2 -> /dev/pts/2

/proc/self/fd:
total 0
lrwx------ 1 isaac isaac 64 Oct 14 09:50 0 -> /dev/pts/2
lrwx------ 1 isaac isaac 64 Oct 14 09:50 1 -> /dev/pts/2
lrwx------ 1 isaac isaac 64 Oct 14 09:50 2 -> /dev/pts/2
lr-x------ 1 isaac isaac 64 Oct 14 09:50 3 -> /proc/3345/fd

[1]  + done       ls -l /proc/self/fd /proc/$$/fd/*
mail% 

~からメーリングリスト:

Fd 255は内部的にttyへの接続として使用されるため、execを使用してfdを再配置することは妨げられません。同じ理由で、Bashはプロセス置換 "<(foo)"を処理するときに高いfdを割り当てます。
アンドレアス・シュワップ

答え2

このファイル記述子は制御 tty のオープンハンドルであり、255対話モードで実行されている場合にのみ使用されます。bash

これにより、ジョブ制御の実行を許可しながらメインシェルからリダイレクトすることができますstderr(つまり、^Cでプロセスを終了し、^Zでプロセスを中断する機能など)。

例:

$ exec 2> >(tee /tmp/err); ls /nosuchfile; sleep 1000

ksh93単にファイル記述子2を制御端末への参照として使用するこのようなシェルでこれを試みると、sleepプロセスは^ Cと^ Zの影響を受けず、別のウィンドウ/セッションで終了する必要があります。これは、ファイルディスクリプタ2が端末を指していないため、シェルがそれを使用してプロセスグループを端末sleepの前景プロセスグループに設定できないためです。tcsetgrp()

これは具体的ではなく、合計bashにも当てはまります。ただ記述子がそんなに高く移動していないだけです(通常10)。dashzsh

zshこのfdはプロンプトとユーザー入力をエコーするためにも使用されます。

$ exec 2>/tmp/err
$ 

他の回答やコメントで提案したように、スクリプトを読み込んでパイプを設定するときに使用されるファイルハンドルとは関係ありませんbash(このパイプは同じ機能を使用してコピーされます - )。move_to_high_fd()

bashこのように大きな数値を使用することは、fdが(たとえば)シェル内のリダイレクト9に使用される値よりも大きくなるようにすることです。他のシェルはこれをサポートしていません。exec 87<filename

ファイルハンドルを直接使用することもできますが、ファイルハンドルを取得できるため、そうすることはあまり意味がありません。同じ... < /dev/tty以下を使用して、すべてのコマンドで端末を制御します。

bashソースコードの分析:

では、bash制御端末のファイル記述子がshell_tty変数に格納されます。シェルが対話型の場合、変数は端末にjobs.c:initialize_job_control()接続されているstderr場合はstderrコピーまたは直接開いて(起動時または実行失敗後)初期化されます/dev/tty。その後、親fdにコピーし直してくださいgeneral.c:move_to_high_fd()

int
initialize_job_control (force)
     int force;
{
  ...
  if (interactive == 0 && force == 0)
    {
      ...
    }
  else
    {
      shell_tty = -1;

      /* If forced_interactive is set, we skip the normal check that stderr
         is attached to a tty, so we need to check here.  If it's not, we
         need to see whether we have a controlling tty by opening /dev/tty,
         since trying to use job control tty pgrp manipulations on a non-tty
         is going to fail. */
      if (forced_interactive && isatty (fileno (stderr)) == 0)
        shell_tty = open ("/dev/tty", O_RDWR|O_NONBLOCK);

      /* Get our controlling terminal.  If job_control is set, or
         interactive is set, then this is an interactive shell no
         matter where fd 2 is directed. */
      if (shell_tty == -1)
        shell_tty = dup (fileno (stderr));        /* fd 2 */

      if (shell_tty != -1)
        shell_tty = move_to_high_fd (shell_tty, 1, -1);
      ...
    }

shell_ttyまだ制御ttyでない場合は、次のように設定します。

          /* If (and only if) we just set our process group to our pid,
             thereby becoming a process group leader, and the terminal
             is not in the same process group as our (new) process group,
             then set the terminal's process group to our (new) process
             group.  If that fails, set our process group back to what it
             was originally (so we can still read from the terminal) and
             turn off job control.  */
          if (shell_pgrp != original_pgrp && shell_pgrp != terminal_pgrp)
            {
              if (give_terminal_to (shell_pgrp, 0) < 0)

shell_ttyその後、使用

  1. tc[sg]etpgrpinjobs.c:maybe_give_terminal_to()とを使用してjobs.c:set_job_control()フォアグラウンドプロセスグループを取得して設定します。jobs.c:give_terminal_to()

  2. termios(3)とでパラメータを取得して設定するjobs.c:get_tty_state()jobs.c:set_tty_state()

  3. ioctl(TIOCGWINSZ)端末ウィンドウのサイズを取得するには、inを使用しますlib/sh/winsize.c:get_new_window_size()

move_to_high_fd()一般的に使用されるすべての一時ファイル記述子(スクリプトファイル、パイプなど)と組み合わせて使用​​されるため、bashGoogle検索で強調されたほとんどのコメントで混乱が発生します。

内部で使用されるファイル記述子はbash実行shell_tty時に閉じるように設定され、コマンドに漏れません。

関連情報