結論としては、以下のコマンドでカレントディレクトリの拡張子なしファイルを全て削除することができる。

$ ls -F . | grep -v -E '^.+/$' | grep -v -E '^.+\..+$' | sed s/\*$//g | xargs -I{} rm {}

コピペで使う場合は、実行するとすぐに削除されてしまうので、| xargs -I{} rm {} を抜いて削除対象の一覧を確認してから削除することをおすすめする。

拡張子なしのファイルを削除したい

C、C++、Rustなどのちょっとしたコードを書いて実行する場合、コンパイル時に(何も指定しなければ)拡張子なしの実行ファイルが生成される。色々なコードを書き捨てていると、これらの実行ファイルで作業ディレクトリが溢れてしまう。そのため、これらの拡張子なしのファイルを一括で削除するコマンドを作成したい。なお、この記事では拡張子のないファイルというのは、ファイル名が<filename>.<ext>という形式になっていないファイルを指すことにする。

「拡張子がない」を正規表現で表す

まずは拡張子のないファイルを発見する方法について考える。今回はgrepコマンドを使って、正規表現にマッチするファイルを探すことにする。grepで、与えられた候補から拡張子が指定されていないものを見つけるには以下のコマンドが使用できる。

$ grep -v -E '^.+\..+$'

-E <regexp> は検索に使う正規表現を指定しており、-v はマッチしなかったものを返したいときに指定するオプションだ。つまり、上記コマンドを実行すると、検索対象のうち、正規表現 '^.+\..+$' にマッチしないものが返される。正規表現部分は、「先頭から末尾までに.が一つ以上含まれている文字列」を表している。

検索候補をうまく渡して削除対象を決める

次に、検索対象とするファイル名の一覧をgrepコマンドに渡す。一番単純なのは、現在のディレクトリ内のファイルを全て与えるような方法だ。

$ ls . | grep -v -E '^.+\..+$'

一見よさそうに見えるが、実はこのままでは不十分だ。というのもlsコマンドではディレクトリも一緒に出力されてしまうためだ。そこで、lsコマンドに-Fオプションをつけてディレクトリ名の末尾に/を追加するようにする。そして、grepコマンドでそのような名前を弾くことにする。

$ ls -F . | grep -v -E '^.+/$' | grep -v -E '^.+\..+$'

ここで、-F オプションをつけたことによって、実行可能ファイル名の末尾には* が追加されている。そこで、その * だけsedコマンドで削除することにする。以下のコマンドを実行すると、削除対象となるファイルの一覧が表示される。

$ ls -F . | grep -v -E '^.+/$' | grep -v -E '^.+\..+$' | sed s/\*$//g

見つかったファイルを全て削除する

最後に、上述のコマンドで選ばれた全てのファイルをxargs経由のrmコマンドで削除する。実行する前は、削除されるファイル一覧をよく確認してから実行してほしい。

$ ls -F . | grep -v -E '^.+/$' | grep -v -E '^.+\..+$' | sed s/\*$//g | xargs -I{} rm {}

rmで実際に削除

実行可能コマンドとして配置する

よく実行する場合は、実行可能コマンドとして作業環境に用意しておくと便利だ。僕の場合はrmxというファイル名で、以下のようなbashスクリプトをローカル環境に配置している(コピペで使用可能)。念の為、思わぬ事故を防げるように削除予定のファイル名を出力してyes/noを訪ねてから実行するようにしている。

#!/bin/bash

function file_list() {
    ls -F $1 | grep -v -E '^.+/$' | grep -v -E '^.+\..+$' | sed s/\*$//g
}

function run_rmx() {
    file_list | xargs -I{} rm {}
}

file_list
read -p "> delete these files? (y/N): " answer
case $answer in
  [yY]*) run_rmx;;
  *) echo "aborted";;
esac

このファイルを適当な場所に置いて、権限を変更し、PATHを通したら完了だ。たとえば、~/binrmx というファイル名で作成した場合、以下の手順を行う。

$ cd ~/bin
$ sudo chmod 755 rmx

$ vim ~/.zshrc
# .bashrcや.zshrcでPATHを通しておく
# export PATH="$HOME/bin:$PATH"

作成したスクリプトの実行例

今回作成したスクリプトでは、ディレクトリを指定して削除する形にした。僕みたいに、よく拡張子なしファイルを消してまわる人には便利だ。

$ rmx .
ABC001A
ABC001B
> delete these files? (y/N): y

rmxコマンドの実行例

僕のユースケースではこれで事足りているが、再帰的にディレクトリを潜って探索したい場合はfind等を使用すると良いだろう(その場合は正規表現等を修正する必要がある)。

参考