19
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

exec 3>&1 てなんやねん!?

Last updated at Posted at 2017-02-08

はじめに

シェルスクリプトを眺めているとたまに出てくる表記。何かをリダイレクトしているというのは分かるけど、一念発起して細かく動作を調べてみた。

手順

端末を2つ開く

一つ目の端末は、以下のようにcdしておく。

端末A
$ cd /proc/$$/fd

fdを表示する

端末A
$ ls -l
total 0
lrwx------ 1 user group 64 Feb  8 16:51 0 -> /dev/pts/1
lrwx------ 1 user group 64 Feb  8 16:51 1 -> /dev/pts/1
lrwx------ 1 user group 64 Feb  8 16:51 2 -> /dev/pts/1

fd3をopenする

fd1をfd3へコピーする。これは、fd1をバックアップしておいて後で戻すという意図がある。

端末A
$ exec 3>&1
$ ls -l
total 0
lrwx------ 1 user group 64 Feb  8 12:18 0 -> /dev/pts/1
lrwx------ 1 user group 64 Feb  8 12:18 1 -> /dev/pts/1
lrwx------ 1 user group 64 Feb  8 12:18 2 -> /dev/pts/1
lrwx------ 1 user group 64 Feb  8 12:18 3 -> /dev/pts/1

fd1をファイルにリダイレクトする

この瞬間から、端末Aにはコマンドの出力がされなくなる。

端末A
$ exec 1>/tmp/redirect1.out
$ ls -l
$ # ls の結果は表示されない

端末Bでファイルをtailする

端末Aの出力がファイルにリダイレクトされている。

端末B
$ tail -f /tmp/redirect1.out

# ここから下はリダイレクトされたもの
total 0
lrwx------ 1 user group 64 Feb  8 14:56 0 -> /dev/pts/1
lrwx------ 1 user group 64 Feb  8 14:56 1 -> /tmp/redirect1.out
lrwx------ 1 user group 64 Feb  8 14:56 2 -> /dev/pts/1
lrwx------ 1 user group 64 Feb  8 15:00 3 -> /dev/pts/1

fd2にfd1を複製する

最初に exec 1>/tmp/redirect1.out 2>&1 とすることと結果的に同じ。また、ここから端末Aには一切出力されなくなるので、端末Bで確認する。

端末A
# あとで見やすいようにプロンプトを変えておく
$ PS1='(tail)$ '

(tail)$ exec 2>&1

# 何も出力されなくなるが、以下を入力する
ls -l

端末Bで確認する

端末Aの出力がファイルにリダイレクトされている。

端末B
(tail)$ ls -l
total 0
lrwx------ 1 user group 64 Feb  8 16:05 0 -> /dev/pts/1
l-wx------ 1 user group 64 Feb  8 16:05 1 -> /tmp/redirect1.out
l-wx------ 1 user group 64 Feb  8 16:05 2 -> /tmp/redirect1.out
lrwx------ 1 user group 64 Feb  8 16:05 3 -> /dev/pts/1

fd6をopenする

新たにfd6をopenし、ファイルにリダイレクトする。fd4, fd5を飛ばしことに深い意味はない。

端末A
# エコーバックも含めてファイルにリダイレクトされているため、表示は一切されない
exec 6>/tmp/redirect6.out
ls -l

ls -lの結果はファイルにリダイレクトされている。

端末B
(tail)$ ls -l
total 0
lrwx------ 1 user group 64 Feb  8 15:01 0 -> /dev/pts/1
l-wx------ 1 user group 64 Feb  8 15:01 1 -> /tmp/redirect1.out
l-wx------ 1 user group 64 Feb  8 15:01 2 -> /tmp/redirect1.out
lrwx------ 1 user group 64 Feb  8 15:02 3 -> /dev/pts/1
l-wx------ 1 user group 64 Feb  8 15:15 6 -> /tmp/redirect6.out

fd1, fd2を使用する

fd1, fd2へ出力する。

端末A
# 何も出力されないが、以下を入力する
echo "test1"
echo "test2" >&2

fd1, fd2がファイルへリダイレクトされていることを確認する。

端末B
(tail)$ echo "test1"
test1
(tail)$ echo "test2" >&2
test2
(tail)$

fd6を使用する

fd6へ出力する。

端末A
# 何も出力されないが、以下を入力する
echo "test3" >&6

fd6がファイルへリダイレクトされていることを確認する。

端末B
(tail) $ echo "test3" >&6

# Ctrl-Cでtailを終了する
(tail) $ ^C

# 以下を入力する
$ cat /tmp/redirect6.out
test3

fd1, fd2を元に戻す

バックアップしておいたfd3を複製することで元に戻せる。

端末A
# 何も出力されないが、以下を入力する
exec 1>&3
exec 2>&3

# プロンプトを適当に直す
(tail)$ PS1='$ '

# fd1, fd2 が元に戻っている
$ ls -l
total 0
lrwx------ 1 user group 64 Feb  8 15:01 0 -> /dev/pts/1
lrwx------ 1 user group 64 Feb  8 15:01 1 -> /dev/pts/1
lrwx------ 1 user group 64 Feb  8 15:01 2 -> /dev/pts/1
lrwx------ 1 user group 64 Feb  8 15:02 3 -> /dev/pts/1
l-wx------ 1 user group 64 Feb  8 15:15 6 -> /tmp/redirect6.out

不要になったfd3, fd6を閉じる

これで完全に初期状態に戻る。

端末A
$ exec 3>&-
$ exec 6>&-
$ ls -l
lrwx------ 1 user group 64 Feb  8 12:29 0 -> /dev/pts/1
lrwx------ 1 user group 64 Feb  8 12:29 1 -> /dev/pts/1
lrwx------ 1 user group 64 Feb  8 12:29 2 -> /dev/pts/1

おまけ

最近のbashは、{varname} という形式を使えば、fdの番号を10以上から自動的に採番してくれるらしい。

$ exec {redirect1}>&1
$ exec {redirect2}>&1

$ ls -l
total 0
lrwx------ 1 user group 64 Feb  8 16:29 0 -> /dev/pts/3
lrwx------ 1 user group 64 Feb  8 16:29 1 -> /dev/pts/3
lrwx------ 1 user group 64 Feb  8 16:30 10 -> /dev/pts/3
lrwx------ 1 user group 64 Feb  8 16:30 11 -> /dev/pts/3
lrwx------ 1 user group 64 Feb  8 16:29 2 -> /dev/pts/3

$ exec {redirect1}>&-
$ exec {redirect2}>&-

$ ls -l
total 0
lrwx------ 1 user group 64 Feb  8 16:29 0 -> /dev/pts/3
lrwx------ 1 user group 64 Feb  8 16:29 1 -> /dev/pts/3
lrwx------ 1 user group 64 Feb  8 16:29 2 -> /dev/pts/3

感想

ずっとモヤモヤしていたのがすっきりしたけど、自分でシェルスクリプトを作る範囲内では使うことはなさそう。他の人が読めるとは限らないし。

19
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?