LoginSignup
0

More than 5 years have passed since last update.

Bashで2つのディレクトリ間の同名ファイルを抽出する

Posted at

tl;dr

重複取得/排除にはuniqが便利です。

確認用の準備

動作確認用に、2つのディレクトリaとbを用意し、お試し用のファイル(ディレクトリ)を作る

mkdir -p a/{1,2,3,4,5,6,7,8,9,10}
mkdir -p b/{1,3,5,7,9,11,13,15,17}

同名のモノを抽出

 (ls a; ls b) | sort | uniq -d

1
3
5
7
9

同名のモノを除外

 (ls a; ls b) | sort | uniq -u

10
11
13
15
17
2
4
6
8

こっちはもう少しいい感じにしたい。もう一回同じような処理を書けば完全に除外はできるけど。

背景

元の問題としては、同じ日付フォーマットを持つディレクトリ名が異なるディレクトリ間に大量にできており、この中から不要なディレクトリを除去してほしいとのことだった。
調べてみると、片方は不要なディレクトリの判別が簡単だが、もう片方は判別が難しいというものだった。でも削除するべき日付をメモして手で削除なんてやりたくないし、そもそも片方は残すべきものが分かっているので、そこと重複するやつだけ残せば良いよね、という事で。

最初は一致するものを抽出・除外といったらgrepだろうけど、複数行同士だとうまくいかないなーめんどいなー、という感じでパッと思いつかなかった。でもperlでちょっと書くのはしのびない作業。

うーんと考えていたら、2つのディレクトリ内で考えれば、同名のファイルは2つしか存在しえないので、sort | uniq- cでカウントが2なら表示すれば出来ると考えた。(1なら同名のモノを除外)

# a,bから同名のモノを抽出
 (ls a; ls b) | sort | uniq -c | awk '$1 == 2 {print $2}'
# a,bから同名のモノを除外
 (ls a; ls b) | sort | uniq -c | awk '$1 == 1 {print $2}'

これなら、3つのディレクトリ間で同名のモノが3つあるものだけ取り出す、というのも簡単に出来る。(そんな用途あるかは知らんけど。)

でもawkめんどいな、もっといい方法ないかな、とmanを眺めてたらuniqのオプションで出来そうということで、最初の方法にたどり着いた。多分もう少し良い方法があるはず。

後は、この結果を使ってxargs -n1 -I{} mv a/{} tempで移動させた後、rm -rf tempといった感じに使う。存在しないものはmvで失敗するだけなのでこれで良い。

ワンライナー力が足りない。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0