web-dev-qa-db-ja.com

コード「{exec> / dev / null;}> / dev / null」では、内部で何が起こっていますか?

Execリダイレクションを含むコマンドリストをリダイレクトしても、exec>/dev/nullは、次のように、まだ適用されていないようです。

{ exec >/dev/null; } >/dev/null; echo "Hi"

「こんにちは」と印刷されています。

{}コマンドリストは、パイプラインの一部でない限りサブシェルとは見なされないため、exec >/dev/nullは、私の心の現在のシェル環境内で引き続き適用する必要があります。

次のように変更すると、

{ exec >/dev/null; } 2>/dev/null; echo "Hi"

期待どおりの出力はありません。ファイル記述子1は、今後のコマンドでも/ dev/nullにポイントされたままです。これは、再実行することで示されます。

{ exec >/dev/null; } >/dev/null; echo "Hi"

出力はありません。

台本を作ってみてみましたが、ここで何が起こっているのか正確にはわかりません。

このスクリプトの各ポイントで、STDOUTファイル記述子はどうなりますか?

編集:私のstrace出力を追加します:

read(255, "#!/usr/bin/env bash\n{ exec 1>/de"..., 65) = 65
open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
fcntl(1, F_GETFD)                       = 0
fcntl(1, F_DUPFD, 10)                   = 10
fcntl(1, F_GETFD)                       = 0
fcntl(10, F_SETFD, FD_CLOEXEC)          = 0
dup2(3, 1)                              = 1
close(3)                                = 0
close(10)                               = 0
open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
fcntl(1, F_GETFD)                       = 0
fcntl(1, F_DUPFD, 10)                   = 10
fcntl(1, F_GETFD)                       = 0
fcntl(10, F_SETFD, FD_CLOEXEC)          = 0
dup2(3, 1)                              = 1
close(3)                                = 0
dup2(10, 1)                             = 1
fcntl(10, F_GETFD)                      = 0x1 (flags FD_CLOEXEC)
close(10)                               = 0
fstat(1, {st_mode=S_IFCHR|0666, st_rdev=makedev(1, 3), ...}) = 0
ioctl(1, TCGETS, 0x7ffee027ef90)        = -1 ENOTTY (Inappropriate ioctl for device)
write(1, "hi\n", 3)                     = 3
15
Joey Pabalinas

フォローしましょう

{ exec >/dev/null; } >/dev/null; echo "Hi"

一歩一歩。

  1. 2つのコマンドがあります。

    a。 { exec >/dev/null; } >/dev/null、続いて

    b。 echo "Hi"

    シェルは最初にコマンド(a)を実行し、次にコマンド(b)を実行します。

  2. { exec >/dev/null; } >/dev/nullの実行は次のように進行します。

    a。最初に、シェルはリダイレクト>/dev/nullを実行し、コマンドが終了したときにそれを元に戻すことを忘れないでください

    b。次に、シェルは{ exec >/dev/null; }を実行します。

    c。最後に、シェルは標準出力を元の場所に切り替えます。 (これはls -lR /usr/share/fonts >~/FontList.txtと同じメカニズムです-リダイレクトは、それらが属するコマンドの間だけ行われます。)

  3. 最初のコマンドが完了すると、シェルはecho "Hi"を実行します。標準出力は、最初のコマンドの前の場所です。

17
AlexP

サブシェルまたはサブプロセスを使用しないために、複合リスト_{}_がパイプライン_>_である場合、シェルは複合リストを実行する前にSTDOUT記述子を保存し、その後に復元します。したがって、複合リスト内の_exec >_は、古い記述子がSTDOUTとして復元された時点を過ぎても効果がありません。

_strace bash -c '{ exec >/dev/null; } >/dev/null; echo hi' 2>&1 | cat -n_の関連部分を見てみましょう。

_   132  open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
   133  fcntl(1, F_GETFD)                       = 0
   134  fcntl(1, F_DUPFD, 10)                   = 10
   135  fcntl(1, F_GETFD)                       = 0
   136  fcntl(10, F_SETFD, FD_CLOEXEC)          = 0
   137  dup2(3, 1)                              = 1
   138  close(3)                                = 0
   139  open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
   140  fcntl(1, F_GETFD)                       = 0
   141  fcntl(1, F_DUPFD, 10)                   = 11
   142  fcntl(1, F_GETFD)                       = 0
   143  fcntl(11, F_SETFD, FD_CLOEXEC)          = 0
   144  dup2(3, 1)                              = 1
   145  close(3)                                = 0
   146  close(11)                               = 0
   147  dup2(10, 1)                             = 1
   148  fcntl(10, F_GETFD)                      = 0x1 (flags FD_CLOEXEC)
   149  close(10)                               = 0
_

134行目で、記述子_1_(STDOUT)が、少なくとも_10_のインデックスを持つ別の記述子にどのようにコピーされるかを確認できます(これは_F_DUPFD_が行うことです)。その記述子に複製した後の指定された番号)。また、137行目で、open("/dev/null")(記述子_3_)の結果が記述子_1_(STDOUT)にコピーされる方法も確認してください。最後に、_147_行で、記述子_10_に保存された古いSTDOUTが記述子_1_(STDOUT)にコピーされます。最終的な効果は、_144_行のSTDOUTへの変更を絶縁することです(これは、内部の_exec >/dev/null_に対応します)。

14
DepressedDaniel

_{ exec >/dev/null; } >/dev/null; echo "Hi"_と_{ exec >/dev/null; }; echo "Hi"_の違いは、次のコマンドを実行する前に、元のstdoutのコピーであるfd 10を閉じる前に、二重リダイレクトがdup2(10, 1);を実行することです。 (echo)。

これは、外部リダイレクトが実際に内部リダイレクトをオーバーレイしているためです。それが完了すると、元のstdout fdをコピーして戻す理由です。

8
Julie Pelletier