CLIで0byteファイルを作る最適解を考える

単一ファイルは >>filename で、複数ファイルは touch filename ... と使い分けるのが良いのではないだろうか

おことわり

この手のエントリはごまんとあるのでn番煎じだし、結論どんな手であろうと作れれば良いので、ここでの話は思想じみたものになる。
また、下記は主にPOSIXの定義に基づき記述している。

コマンド touch について

POSIX (2018) を下記に抜粋する。

The touch utility shall change the last data modification timestamps, the last data access timestamps, or both.

https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/utilities/touch.html

1. If file does not exist:
a. The creat() function is called with the following arguments:
○ The file operand is used as the path argument.
○ The value of the bitwise-inclusive OR of S_IRUSR, S_IWUSR, S_IRGRP, S_IWGRP, S_IROTH, and S_IWOTH is used as the mode argument.

https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/utilities/touch.html

かいつまんで言えば、このコマンドの目的はファイルのタイムスタンプ更新、副次的な効果としてファイルが存在しなかった場合に作成する。
これを承知の上で使っているなら何も問題ないと思う(ファイルを作るコマンドとして教えている人はいただけない)。

touchのメリットは、複数ファイルを一度に扱うことができる点である。

$ touch file{000..999}.txt

リダイレクトについて

シェルのネイティブな機能でファイルを作成する方法にリダイレクトがある。
リダイレクトに関しては、下記のように示されている。

1. The words that are recognized as variable assignments or redirections according to Shell Grammar Rules are saved for processing in steps 3 and 4.

2. The words that are not variable assignments or redirections shall be expanded. If any fields remain following their expansion, the first field shall be considered the command name and remaining fields are the arguments for the command.

https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/utilities/V3_chap02.html#tag_18_09_01

If there is a command name, execution shall continue as described in Command Search and Execution . If there is no command name, but the command contained a command substitution, the command shall complete with the exit status of the last command substitution performed. Otherwise, the command shall complete with a zero exit status.

https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/utilities/V3_chap02.html#tag_18_09_01

これも要約すると、「最初に変数代入とリダイレクトの箇所を取り除き、残った文字列の最初の単語をコマンド名と認識する」「コマンド名がない場合は0ステータスで終了する」ということになる。

したがって、コマンド名を書かずリダイレクトだけ入力すると、何もしない(true コマンドや :コマンドと同等)状態でリダイレクトだけ実行するということになる。
そのため、>filename を実行すると空ファイルが作成されることになる。

補足:zshはコマンド名がないときのデフォルト動作が cat になるらしい。
setopt SH_NULLCMD を設定すれば POSIXと同じ挙動になる

If the parameter NULLCMD is not set or the option CSH_NULLCMD is set, an error is caused. This is the csh behavior and CSH_NULLCMD is set by default when emulating csh.

If the option SH_NULLCMD is set, the builtin ‘:’ is inserted as a command with the given redirections. This is the default when emulating sh or ksh.

Otherwise, if the parameter NULLCMD is set, its value will be used as a command with the given redirections. If both NULLCMD and READNULLCMD are set, then the value of the latter will be used instead of that of the former when the redirection is an input. The default for NULLCMD is ‘cat’ and for READNULLCMD is ‘more’.

https://zsh.sourceforge.io/Doc/Release/Redirection.html#Redirections-with-no-command

リダイレクトのメリットは、入力速度(と思想の影響を受けず使いやすい)ではないだろうか。

リダイレクトによる上書き防止について

>filename には一つ問題点があり、同名のファイルが既に存在していた場合にデフォルトで上書きしてしまう。
このため、上書きモードでリダイレクトするのは少々リスキーになる。

回避策は簡単で、追記モードリダイレクトすれば良い。

$ >>filename

あるいは、set -C を .bashrc に書いておけば、>filename を実行しても誤って上書きしてしまうことがなくなる。

コメント

タイトルとURLをコピーしました