〜駆け出しのLinux復習〜 標準入力、標準出力、標準エラー出力、リダイレクトについて

※2021年5月11日追記
この記事はまだ不完全です！より良質な内容に変えていきたいと考えていますのでご了承ください！
（具体的にはコメント欄を御覧ください。これから編集作業に入っていきます）

駆け出しエンジニアです。
今回も「新しいLinuxの教科書」で学習した内容を基にアウトプットしてみようと思います。
時間をかけて慎重に書いていますが、間違いなどがありましたらご指摘いただけると幸いです！

今回は標準入出力について深堀り？します！
正直これらのワードは最初にLinuxを学習した時にも出てきたので覚えてはいましたが、イマイチピンときてない感じだったので。。。笑

# メニュー項目
- 標準入力
- 標準出力
- 標準エラー出力
- リダイレクト

これらについて取り扱います！

## ざっくりと概要
ここでいう「入力」「出力」とは**「データの流れる経路」**を表します。

- 標準入力(stdin): standard input。ざっくり言うとキーボードが繋がっている
- 標準出力(stdout): standard output。ざっくり言うとディスプレイが繋がっている
- 標準エラー出力(stderr): standard error output。ざっくり言うとディスプレイが繋がっている
- リダイレクト： 標準入出力先を変更すること。

私も誤解していたのが、標準入出力というのはあくまで「経路」であるということです。
キーボードが繋がっているからと言って、**キーボードの入力内容のことを標準入力と言うのではない**、ということです。

標準入出力の繋ぎ方に関してはシェルで自由に制御することが可能です。
標準入力にファイルを繋ぎ変えることも、標準出力、標準エラー出力にファイルを繋ぎ変えることも可能です。（＝リダイレクト）

というより、Linuxの世界ではキーボードやディスプレイすらファイルとして扱うようです・・・
そういう意味では、ファイルを繋ぎ替えるとかではなく、そもそも標準入出力に繋がっているのは「ファイル」であると言えます。
[In Linux, Everything is a File](https://www.linux.org/threads/in-linux-everything-is-a-file.4251/)


## 標準入力のリダイレクト
catコマンドを例にとります。

ざっくりとこれまでの私のcatコマンドの認識は、**「引数に指定したファイルの中身を表示してくれる」**でした。
これは間違いではないのですが、よりLinuxっぽく？と言うのでしょうか。そのような解釈をしてみたいと思います。

### 引数無しのcat
catコマンドに引数を何も渡さずに実行すると、キーボードの入力待ちになり入力した内容を表示するようになります。

```bash
$ cat
            # 入力待ちになる

$ cat
hello    # 入力すると・・・
hello    # 入力した内容が表示される！（ctrl + d で終了できます！）
```

この挙動を踏まえて、catのマニュアルを見てみました。

```bash
$ man cat
```

するとDESCRIPTIONの項目に以下の内容が記されていました。

```
The cat utility reads files sequentially, writing them to the standard output.
・・・省略・・・
If file is a single dash (`-') or absent, cat reads from the standard input.
```

ざっくりと訳すと、「ファイルを読み込んで標準出力へ出力するよ。ファイルが'-'か空の場合は、標準入力から読み込むよ」と言っています。
先程はファイルを空で渡したことになるので、**標準入力から読み込んで標準出力へ出力した**ということになります。


### ファイルの場合を考える
冒頭あたりで、標準入出力にはファイルを繋ぐこともOKということを述べました。（繰り返しますがLinuxでは全てがファイルです。この記事では便宜上キーボードやディスプレイとファイルを分けて説明しています）
ここでリダイレクトが登場します。

### 標準入力をリダイレクトしてみる（入力リダイレクト）
標準入力をリダイレクトする場合は、

```
<
```

これを使います。

catコマンドに対して、キーボードではなくファイルを標準入力につなぐ場合は以下のようになります。

```bash
$ cat hoge.txt # 普通に渡すとこう
これはhoge.txtの中身です

$ cat < hoge.txt # hoge.txtを標準入力につなぐ!!!
これはhoge.txtの中身です
```

出力結果が何も変わりません。同じです。
つまり厳密には「cat < hoge.txt　という形で標準入力をリダイレクトし、標準出力へ出力する」というのが本来の動きになるのですが、
「catコマンドはその利便性のためにその手間が不要になっている」ということになるようです。

## 標準出力のリダイレクト（出力リダイレクト）
利用用途例：**コマンドの実行結果をファイルに保存する**

### 使い方

```bash
>    #これを使います

$ コマンド > ファイル    #コマンド結果の行き先がファイルに向いてるイメージで覚えます
```

echoコマンドを例にとります。

```bash
$ echo “Hello World! Hellooooo” > echo.txt    #標準出力をecho.txtへリダイレクト
# 何も出力されない

$ cat echo.txt    #echo.txtの中身を見ると
Hello World! Hellooooo
```

このような感じで実行結果をファイルに保存させることができます！
ちなみにファイルは自動的に作成されますが、**同じ名前のファイルが存在した場合、新しく上書きされますので注意**

```bash
$ cat echo.txt
Hello World! Hellooooo

$ echo “HELLO WORLD” > echo.txt    #別の文字列で同じファイルにリダイレクトすると
HELLO WORLD    #内容が上書きされてしまう
```

### 上書きは恐ろしいので・・・
上書きではなく「追記」という出力方法も選べます。

```bash
>>    #コマンドの実行結果を追記するにはこれ

$ コマンド >> ファイル
```

```bash
$ cat echo.txt
HELLO WORLD

$ echo “追記だよ” >> echo.txt    #追記させる
HELLO WORLD    #元の内容も残っている
追記だよ
```

例えば環境変数をファイルに追加したい時、そのファイルを開いてエディターで編集しなくとも、
echoコマンドで標準出力をそのファイルにリダイレクトすることでコマンドライン上で追記の処理を行う、というような使い方ができそうですね！
また追記とは言っても新規ファイルを指定した場合はちゃんと自動で作成してくれます。
またシェル側で上書きを阻止する設定も行えるようです。


## 標準エラー出力
標準エラー出力は、プログラムのエラーメッセージを出力するものです。
標準出力と標準エラー出力はどちらもざっくりとディスプレイに繋がっていると冒頭で述べました。
これだと、両者の見分けがつかないように感じます。が、どうでしょうか。

たとえば存在しないファイルにcatコマンドしたとすると

```bash
$ cat unexist.txt
cat: unexist.txt: No such file or directory
```

「そんなファイルもディレクトリもねーよ」と言われてしまいます。

同じ内容で標準出力をリダイレクトしてみます。

```bash
$ cat unexist.txt > example.txt
cat: unexist.txt: No such file or directory
```

同じ様にエラー文は画面に出力されましたが、example.txtは空ファイルで作成されています。

つまり標準出力と標準エラー出力は別々のチャネル（経路）になっているということです。
（標準出力はファイルに繋がって、標準エラー出力はディスプレイに繋がっていた）





### 標準エラー出力のリダイレクト
```bash
2>    #これを使う
2>>   # 上書きさせたくない場合は

$ コマンド 2> ファイル
```

何故2という数字が出るのかというと、次の項目で出てきますが各入出力には対応する番号が存在します。
エラー出力には2という番号が割り振られているので、それが理由だと思います。

試しに存在しないファイルをcatコマンドに渡し、標準エラー出力をリダイレクトしてみます。
エラー出力をリダイレクトするので、エラー文は表示されず、リダイレクト先に格納されるはずです。

```bash
$ cat unexist.txt 2> error.txt    #エラー出力をリダイレクト

```

何もエラーが表示されませんでした。
error.txtが作成されているので中身をチェックします。

```bash
$ cat error.txt
cat: unexist.txt: No such file or directory
```

期待通りファイルの中にエラー文が出力されていました！

### 標準出力と標準エラー出力を別ファイルにリダイレクト（いっぺんに）
標準出力と標準エラー出力それぞれのリダイレクトを同時に指定することも可能です。

```bash
$ コマンド > 標準出力のリダイレクト 2> 標準エラー出力のリダイレクト    #このように続けて同時に指定できる
```


## 標準入出力には番号がある
先程も少しだけ触れましたが、標準入出力には番号が対応しています。

標準入力：0
標準出力：1
標準エラー出力：2

標準エラー出力のリダイレクトに 2> を使ったように、試しに標準出力を敢えて 1> としてリダイレクトさせたところ、問題なくいけました。

```bash
$ ls -l 1> list.txt    #これでも問題なく標準出力のリダイレクトができました。
```

### 出力とエラーを同じファイルにリダイレクトしたい

```bash
$ コマンド > 標準出力リダイレクト 2>&1
```

このように標準出力のリダイレクト先に続けて2>&1とすると、標準エラー出力も同じリダイレクト先に指定できます。


## /dev/null
/dev/nullとは・・・？
スペシャルファイルと呼ばれる。（ls -lで確認すると種別が”c”になっている。）
すごく簡単に言うと、「全て無に還す」って感じなのかなと思っています。

入力先にしても、出力先にしても、何も返ってこない。というのが/dev/nullです。

### 使用用途は・・・？
私はまだそれが必要と感じる場面に恐らく遭遇していないのではとも感じます。いやどうなんだろ。気付いてないだけかもしれない。笑

使用ケースとしては、コマンドの出力を画面に表示させたくない場合に、標準出力を/dev/nullを指定してリダイレクトさせることで対応する。というのがあるみたいです。

試しにechoしてみます。

```bash
$ echo “Hello” > /dev/null
                     #何も表示されない
```

標準出力だけでなく、標準エラー出力でも同じことが可能です。もちろん両方も。
出力の内容やエラー以外の目的でコマンドを実行する時に、余計な表示を阻止するというような用途になるみたいです。
よく使われるみたいなので、しっかり覚えておこうと思います。


# 最後に
ここまで読んでくださりありがとうございました。
「新しいLinuxの教科書」を読んで学習した内容をより頭に定着させるために、誰かに教える立場になったつもりでアウトプットしています。
ただハッキリ言って実務未経験の駆け出しなので間違いや誤解を招くような書き方などもしてしまっていると思います。可能な限りそうならないよう努力していますが、、、
もしそういった間違いなどがありましたらご指摘いただけると幸いです。

まだまだ簡単な内容でしょうけども初めてLinuxを学んだ頃と比較して少しづつ理解が深まっていくのは楽しいです！今のところは！笑
（それよりもポートフォリオの改善やら色々して早く転職決めるのが優先なのではと薄々感じている）


# スペシャルサンクス
@angel_p_57様
記事：　[標準入力・標準出力ってなに?](https://qiita.com/angel_p_57/items/03582181e9f7a69f8168)