"hoge 2.txt
"、それは突然現れた
僕、Github の private リポジトリに高専時代・大学時代の歴史をバックアップしてるんですけど、そのローカルファイルを iCloud Drive にも保存してたんですね。
今日ファイルの中身が見たくなって雲のマーク「ぽちー」って押して、ローカルに落としたんです。
一通り閲覧して満足したので、一応変な diff が無いか確認するために git status
を叩きました。
すると「ズラズラズラーーーーーーー」っと無数にアウトプットが。。。。
しかも全部 unstaged files
なんですよ。
「怖いなー、怖いなー。何も追加してないのになー。」
って思ってよく見ると、全部「hogehoge 2.pdf
」みたいに、 " 2
" っていうのが拡張子の直前に付いてたんです。。。
それはなんと、全部 Mac が勝手に複製したファイルだったんです。。。。
対処法
はい。ということで、真面目に対処法をシェアします。
症状としては勝手にファイルが複製されて、全部拡張子の直前に 2
が付いている状態です。
例: hoge.txt
の複製ファイルとして hoge 2.txt
が作られている。
今回はこの、 2 とついたファイルだけを削除するワンライナーを紹介します。
結論から言うと、
$ find . -maxdepth 10 -type f | grep " 2\.*"| sed -e 's/ /\\ /g' | xargs rm
というコマンドを叩けばいいです。
お疲れ様でした。
。。。で終わるのもなんか味気ないので、軽く解説します。
解説
ワンライナーをもう一度。
$ find . -maxdepth 10 -type f | grep " 2\.*"| sed -e 's/ /\\ /g' | xargs rm
これをパイプ毎に分けると、
- 深さを指定して列挙:
find . -maxdepth 10 -type f
-
2.
と付くファイルのみに絞り込み:grep " 2\.*"
- スペースをエスケープ:
sed -e 's/ /\\ /g'
- 削除:
xargs rm
一つづつ解説します。
1. 深さを指定して列挙: find . -maxdepth 10 -type f
これは特に問題ないかと思います。
今回は下階層全て検索したかったので、 -maxdepth 10
を付けて 10 階層下まで見に行くようにしています。
find .
を find ${path/to/directory}
とすれば好きなディレクトリについて検索できます。
2. 2.
と付くファイルのみに絞り込み: grep " 2\.*"
ここも特筆することはないです。
.
はそのままだとエスケープが必要なので、バックスラッシュを付けて \.
としています。
これで ${半角スペース}2.
をファイル名に含むものだけ抽出できます。
3. スペースをエスケープ: sed -e 's/ /\\ /g'
これがこのワンライナーの肝だと思います。
何をしているかと言うと、半角スペースにバックスラッシュを付けてエスケープさせています。
理由としては、このまま rm コマンドに渡してしまうと、半角スペースで区切られて別ファイルとして扱われてしまうためです。
例: hoge 2.txt
というファイルを削除する場合
-
rm hoge 2.txt
を実行してみる -
rm
コマンドの気持ちとしてはhoge
と2.txt
というファイルが渡されたと勘違い - 「そんなファイルは無いよ」と言われるか運悪く
hoge
または2.txt
ファイルが意図せず削除されてしまう
なんかスラッシュばっかりで分かりにくいとは思いますが、置換コマンドは
$ sed -e 's/${置換前}/${置換後}/g'
でその行に含まれた全ての対象を置換してくれます。
このコマンドとの diff を取れば、
- 置換前テキスト:
${半角スペース}
- 置換後テキスト:
\\${半角スペース}
というように指定していることが分かると思います。
さらに、バックスラッシュが連続しているのは、バックスラッシュそのものをエスケープするためで、実質 1 つのバックスラッシュを付けています。
つまり、半角スペースの前にバックスラッシュを付けているのです。
これにより、 rm
コマンドが勘違いせずやってくれるはずです。
4. 削除: xargs rm
なんてことはないですが、最後に絞り込まれ、半角スペースをエスケープしたファイル名が指定され、削除される。
という全体的な流れです。