42Tokyoでbashの一部を再実装する課題でリダイレクトを実装することになったので、
その際に気づいたリダイレクトの挙動について私が調べた範囲で公開します。
大前提
リダイレクトの基本的な使い方
# ファイルを新規作成し入力(もしすでにファイルが存在するなら内容を全削除)
command > file
# ファイルを新規作成し入力(もしすでにファイルが存在するなら追記)
command >> file
# ファイルの内容をコマンドの標準入力に渡す
command < file
# ヒアドキュメントが展開(終了文字がEOF)
command << EOF
>, >>, < のあとは必ず「ファイルの名前」
それさえ守れば、順番なんて関係ない!
逆にその部分を抜き取ったものがコマンドとなります。
(パイプ | や セミコロン;などの特殊な例外はありますが、、、)
つまり以下の挙動はすべて同じと言えます。
→ aaaがtest_fileに書き込まれます
echo aaa > test_file
echo > test_file aaa
> test_file echo aaa
cat test_file
aaa
リダイレクトを複数つなげる挙動
絶対に前から順番に実行。
そして、後ろが優先。
# tmp1 には出力されないけど新規ファイルを生成する
# もしすでに存在するなら内容を削除する(ファイルは残る)
echo aaa > tmp1 > tmp2
cat tmp1
cat tmp2
aaa
echo aaa > tmp1
cat tmp1
aaa
echo bbb >> tmp1 > tmp2
cat tmp1
aaa
cat tmp2
bbb
# Error
< no_file > no_file
bash: no_file: No such file or directory
# 正常終了
> no_file < no_file
# no_fileを生成する。
入出力ファイルがない場合
この場合は問答無用にエラーを出力されコマンドは実行されません。
cat < no_file < file
bash: no_file: No such file or directory
cat < file < no_file
bash: no_file: No such file or directory
環境変数でもおなじこと。
export aaa=bbb
# bbb というファイルから入力を受け付ける
cat < $aaa
無い環境変数には注意
unset aaa
cat < $aaa
bash: $aaa: ambiguous redirect # error
ヒアドキュメント(<<)の挙動
終了条件によって挙動が変わる。
# 通常挙動
cat << EOF
> aaa
> bbb
> EOF
aaa
bbb
終了文字がヌル文字の可能性も
# この場合何もないところでEnterを入力すると終了する
cat << ''
> abc
> def
>
abc
def
文字列の展開
# 文字列の展開
cat << EOF
> $USER
> EOF
kels
# 環境変数で$USERをkelsと今回は登録してある
# 文字列を展開しない
cat << "EOF"
> $HOME
> EOF
$HOME
- ちなみに文字列を展開するしないはクオートが存在するかどうか
# 展開しない挙動(以下の終了条件はすべてEOF)
cat << ""EOF
cat << EOF''
cat << E'O'F
# 終了文字が環境変数の場合
# 環境変数で$USERをkelsと今回は登録してある
cat << $USER
> abc
> kels # 終了しない
> $USER # 終了する
abc
kels
番外(cat コマンドの優先順位)
catコマンドはリダイレクトよりも引数を優先します。
cat file
aaa
cat redirect_file
bbb
# 標準入力から受け取っているけど引数を優先して結果を返している。
cat file < redirect_file
aaa
ちなみにerrorの場合はしっかり返してコマンドを実行しません。
cat file
aaa
cat file < no_file
bash: no_file: No such file or directory