web-dev-qa-db-ja.com

Bashでは、ファイル記述子255の目的は何ですか?それを使用できますか?

ファイル記述子(またはファイルハンドラー)はファイルIOテクニックLinuxシステムでは。

また、各プロセスには3つの標準ストリーム(つまり、stdin、stdout、stderr)があり、それらは0〜3の記述子を持つファイルで表されます。

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

this answer から、この機能はBash Shellに固有であることがわかりましたが、回答と参照されたソースの両方がこれについて実際に説明していませんファイル記述子用です。

私の質問:

  1. 255ファイル記述子とは何ですか?
  2. 私のBashスクリプトでそれを使用できますか、それとも手動で使用/操作することを想定していない内部動作メカニズムだけですか?
10
Tran Triet

あなたの質問の最後の部分について:

使えますか?

man bash

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

そのため、その番号を使用して新しいfdを作成する場合、答えはノーです。

次のように使用する場合:「そのfdに書き込む」:

$ echo hello >/dev/fd/255"

またはそれから読むには:

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

答えはイエスです。
しかし、おそらく、(シェルとは関係なく)/dev/tty _ttyにアクセスします。

ファイル記述子255とは何ですか?

ケースfd 1(/dev/stdout)およびfd 0(/dev/stdin)ブロックされます。

詳細

他のシェルは異なる番号を使用する場合があります(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) 'を処理するときに高いfdsも割り当てます。
アンドレアスシュワブ

12
Isaac

その_255_ファイル記述子は、制御ttyへのオープンハンドルであり、bashがインタラクティブモードで実行されている場合にのみ使用されます。

メインシェルでstderrをリダイレクトしながら、ジョブ制御を機能させます(つまり、^ Cでプロセスを強制終了したり、^ Zでプロセスを中断したりできます)。

例:

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

制御端末への参照としてファイル記述子2を単に使用している_ksh93_のようなシェルでそれを試すと、sleepプロセスは^ Cおよび^ Zの影響を受けなくなり、別のウィンドウ/セッションから強制終了されます。これは、ファイル記述子2がもはやターミナルを指していないため、シェルがsleepのプロセスグループをtcsetgrp()を使用してターミナルのフォアグラウンドグループとして設定できないためです。

これはbash固有ではなく、dashおよびzshでも使用されます。記述子がそれほど高く移動されない(通常は10)ことだけです。

zshもそのfdを使用してプロンプトとユーザー入力をエコーするので、次のように単純に機能します。

_$ exec 2>/tmp/err
$ 
_

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

bashは、_9_より大きいfdsをシェル内リダイレクトで使用できるようにするために、このような大きな数を使用しています(例:_exec 87<filename_);他のシェルではサポートされていません。

そのファイルハンドルは自分で使用できますが、_... < /dev/tty_を使用して、すべてのコマンドでsame制御端末にハンドルを取得できるため、そうすることにはほとんど意味がありません。

bashのソースコード分析

bashでは、制御端末のファイル記述子が_Shell_tty_変数に格納されます。シェルがインタラクティブである場合、その変数はjobs.c:initialize_job_control()stderrから複製することで(起動時または失敗したexecの後で)初期化されます(stderrが端末)または_/dev/tty_を直接開いて、general.c:move_to_high_fd()を使用して再度高い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. フォアグラウンドプロセスグループを取得および設定するには、jobs.c:maybe_give_terminal_to()jobs.c:set_job_control()およびjobs.c:give_terminal_to()の_tc[sg]etpgrp_を使用します。

  2. termios(3)およびjobs.c:get_tty_state()jobs.c:set_tty_state()パラメータを取得および設定します

  3. ioctl(TIOCGWINSZ)lib/sh/winsize.c:get_new_window_size()を使用して、ターミナルウィンドウのサイズを取得します。

move_to_high_fd()は通常、bashによって使用されるすべての一時ファイル記述子(スクリプトファイル、パイプなど)とともに使用されます。そのため、Google検索で目立つほとんどのコメントで混乱が生じます。

_Shell_tty_を含む、bashによって内部的に使用されるファイル記述子はすべて、exec-on-execに設定されているため、コマンドにリークされることはありません。

8
mosvy