はじめに
入力ファイルと出力ファイルを同じにするコマンドは避けるべきであり、例えば実際に押下した場合は以下のメッセージが表示されてcatコマンドに失敗します。
$ cat abc.txt >> abc.txt cat: abc.txt: input file is output file
$ cat abc.txt > abc.txt cat: abc.txt: input file is output file
ただし、上書きである>
か追記である >>
では結果が大きく変わります。
本記事ではそれらの違いについて簡単に説明します。
catコマンドのバージョン
$ cat --version cat (GNU coreutils) 8.22 ...
> : ファイル初期化 >> : ファイル無変更
abc.txt に abc という文字列を記載します。
# echo abc > abc.txt # cat abc.txt abc
この状態でリダイレクトを>
とするとファイルが空になります。
# cat abc.txt > abc.txt cat: abc.txt: input file is output file # cat abc.txt
リダイレクトを>>
とするとファイルは変更されません。
# echo abc > abc.txt # cat abc.txt abc # cat abc.txt >> abc.txt cat: abc.txt: input file is output file # cat abc.txt abc
再度書き込まれているわけではなく、ファイルが更新された日付を見ても書き込まれていないのが分かります。
これらの違いは > abc.txt
とすることで abc.txt の初期化が入ることが原因です。
その後の catコマンドで エラーが発生して書き込みが失敗するのはリダイレクト方式の違いに関わらず同様です。
試しにstrace
コマンド*1で詳細を確認すると、どちらもNo such file or directoryでエラーとなっています。
$ strace cat abc.txt > abc.txt ... open("/usr/share/locale/en/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory) write(2, "cat: ", 5cat: ) = 5 write(2, "abc.txt: input file is output fi"..., 34abc.txt: input file is output file) = 34 write(2, "\n", 1 ) = 1 close(3) = 0 close(1) = 0 close(2) = 0 exit_group(1) = ? +++ exited with 1 +++
$ strace cat abc.txt >> abc.txt ... open("/usr/share/locale/en/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory) write(2, "cat: ", 5cat: ) = 5 write(2, "abc.txt: input file is output fi"..., 34abc.txt: input file is output file) = 34 write(2, "\n", 1 ) = 1 close(3) = 0 close(1) = 0 close(2) = 0 exit_group(1) = ? +++ exited with 1 +++
終わりに
「input file is output file」というエラーメッセージはcatコマンドによる書き込みに失敗したというだけで「 > ファイル名」によってファイル名が初期化されてしまうことは成功しています。
お気をつけください。
*1:strace : システムコールやシグナルをトレースするコマンド