• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:二つのフォルダで一方のみにあるものをリストアップ)

二つのフォルダで一方のみにあるものをリストアップする方法とは?

このQ&Aのポイント
  • あるパーティションの中にある同じファイル名を持つもののペアを全て探しだして表示する方法を教えていただきました。
  • 具体的な方法として、以下のコマンドを使用します:find /media/usb2 -xdev -type f -printf '%f %p ' | sort | awk '{if($1==A){if(A!=B)print X;print};B=A;A=$1;X=$0}'
  • このコマンドの詳細解説として、-xdevオプションは他のファイルシステムにあるディレクトリを探索しないために使用されます。また、'%f'は先行するディレクトリを取り除いたファイル名を表示し、'%p'はファイルのパスを表示します。そして、awkコマンドは列のデータを操作するために使用されます。具体的には、$1は1列目のデータを表し、$0は1行全体のデータを表します。

質問者が選んだベストアンサー

  • ベストアンサー
  • notnot
  • ベストアンサー率47% (4900/10358)
回答No.1

回答した者です。 >-xdev ほかのファイルシステムにあるディレクトリを探索しない。 >(これはなぜ必要なのでしょう?) 質問が「あるパーティションの中」とあったので、シンボリックリンクで他のパーティションに行かないようにと思ったのですが、デフォルトではシンボリックリンクをたどらないので、不要でした。 >awk の部分を解説していただけると大変ありがたいです。 awkの入力は、第一列がファイル名で第二列がそのフルパスです。なので、前後に同じファイル名(第一列)が続いたときにその辺の行をプリントするというのがやりたいことなわけです。 (ソートしてあるので、同じファイル名があれば必ず前後に隣り合う) >awk '{if($1==A){if(A!=B)print X;print};B=A;A=$1;X=$0}' if($1==A){  if(A!=B) print X  print } B=A A=$1 X=$0 Aは1つ前の行のファイル名部分、Bは2つ前のファイル名部分、Xは1つ前の行全体です。 基本的には、下記のようにファイル名部分が1つ前と同じならその行を出力すれば良いのですが、 if($1==A) print A=$1 そうすると一続きの先頭の行だけ、抜けてしまいます。先頭の行は、1つ前の行とファイル名が異なるので。なので、「1つ前の行がファイル名部分が同じ一続きの行のグループの先頭だったのかどうか」を調べる必要があり、そういう処理を追加しています。if(A!=B) print X の部分。 今どの行を処理していてAとBに何が入っているのかだけを追えばわかると思いますので、よく考えてみてください。 >パスに空白が含まれていた場合でもきちんと動作するように改良することは可能でしょうか? 書いた後で、「パスにタブが含まれなければ」にしておけば良かったかと思いました。 「パスにタブが含まれなければ」であれば、ファイル名とフルパスをタブで区切って、awkの列区切りもタブにして、 find /media/usb2 -type f -printf '%f\t%p\n' | sort | awk -F$'\t' '{if($1==A){if(A!=B)print X;print};B=A;A=$1;X=$0}' タブでなくても何でもいいのでとにかく、「パスに含まれない文字」が1つあればそれを使えば良いです。 >さらに、二つのフォルダの中の全ファイルを比較して、 >一方のフォルダの中にしか存在しないファイルのみをリストアップする、 ファイル名だけで、そのフルパスを表示しなくていいなら簡単です。 find folder1 -type f -printf '%f\n' | sort -u > list1 find folder2 -type f -printf '%f\n' | sort -u > list2 comm -23 list1 list2 ・・・・・・ フォルダ1にだけあるファイルを表示 comm -13 list1 list2 ・・・・・・ フォルダ2にだけあるファイルを表示 comm -12 list1 list2 ・・・・・・ フォルダ1と2に共通するファイルを表示 ファイルのリストを作って、あとはcommコマンドの基本機能。 そのフルパスも知りたいと言うことなら、かなりめんどくさそうなので、上記でファイル名を得て、 find -name ファイル名 で調べるのが楽そうです。

noname#214079
質問者

お礼

おかげさまでかなり理解できました。 本当にありがとうございます。 私はふだん表計算ソフトも使わない人間ですので、 どこかのサイトに書いてあった記述を読んだ時に 列と行を混同して考えてしまい スクリプトで何がなされているのかがさっぱり分かりませんでした。 それと、解説していただいた内容を読んで awk を使った所では パイプを通して入力されてくるデータの 一行一行に対して '{ と '} で挟まれている部分の処理を行っているということが分かりました。 ここで、一行一行読み込んで処理しているのは パイプの働きではなく awk の働きなのですね。 awk で print が実行されると その時読み込んでいる行全体が出力されるということも分かりました。 パイプの働きはまだイマイチよく理解できていなかったために、 すぐに判断がつかなかったのですが。 comm というコマンドも今回初めて知り、 とても勉強になりました。 おかげさまで目的の処理もあっという間にバッチリとなされ、 重ね重ねお礼申し上げます。

noname#214079
質問者

補足

もしお時間がありましたら、 次の質問も見ていただけると大変ありがたいです。 http://okwave.jp/qa/q8795779.html

その他の回答 (1)

noname#241088
noname#241088
回答No.2

> -xdevについて 起点となるディレクトリ配下に別パーティションがマウントされている可能性も考慮するなら必要なのでしょう。 ただ、質問中の「あるパーティションの中にある」は実は「あるディレクトリ配下にある」という意味に過ぎないのなら不要ですね。 > パスに空白が含まれていた場合でもきちんと動作するように改良することは可能でしょうか? UNIXではファイル名に /(スラッシュ) と ヌル文字(\0) を使用できないので、notnotさんが提示した方法で区切り文字に \0 を使うのがいいのではないでしょうか。 実際にヌル文字を区切り文字にして試してみましたが、問題なさそうでした。 ただ、ファイル名には改行文字(\n)も使えるようで、この場合も対処するとなると大変でしょうけどね。

noname#214079
質問者

お礼

ありがとうございます。 \0 \n まで使えるとは変な感じですね。 きちんと日本語化されていればコマンド内でも日本語が使えるので 全角文字で ・・パス・・ などとしてしまうのもいいかもしれません。

noname#214079
質問者

補足

もしお時間がありましたら、 次の質問も見ていただけると大変ありがたいです。 http://okwave.jp/qa/q8795779.html