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

この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行全体のデータを表します。
回答を見る
  • ベストアンサー

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

http://okwave.jp/qa/q8786259.html において、あるパーティションの中にある 同じファイル名を持つもののペアを全て探しだして表示するやり方を質問した時に 次の答えをいただきました。 find /media/usb2 -xdev -type f -printf '%f %p\n' | sort | awk '{if($1==A){if(A!=B)print X;print};B=A;A=$1;X=$0}' マニュアルを見ると -xdev ほかのファイルシステムにあるディレクトリを探索しない。 (これはなぜ必要なのでしょう?) %f 先行するディレクトリをすべて取り去ったファイル名 (すなわち、 最後の要素のみ表示)。 %p ファイル名 ということなので、 -printf '%f %p\n' で最終表示結果にも適用されると思われる書式を指定。 sort はただの並べ替え。 awk の部分が一番分かりませんでした。 ; は文を並べるための記号のようで、 A!=B は A≠B ということは分かります。 $1 などが   $nには、n列目のデータが入っている。 $0にはすべての列、つまり1行全体のデータが入っている と書いてあるサイトを見つけましたが、 何をやっているかが分かりません。 awk の部分を解説していただけると大変ありがたいです。 また、このスクリプトはパスに空白が含まれない前提のものでしたので、 パスに空白が含まれていた場合でもきちんと動作するように改良することは可能でしょうか? さらに、二つのフォルダの中の全ファイルを比較して、 一方のフォルダの中にしか存在しないファイルのみをリストアップする、 ということもやりたくなったのですが、 そのスクリプトもこの応用ですぐに書けるものでしょうか? どうぞご教授ください。 よろしくお願い致します。

noname#214079
noname#214079

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

  • ベストアンサー
  • notnot
  • ベストアンサー率47% (4851/10265)
回答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

関連するQ&A

  • bash scriptで1日以内更新フォルダコピー

    bash script で1日以内に更新されたフォルダとその中に含まれているファイルやディレクトリのすべてをコピーしたいのですが、そのフォルダの1階層上の親ディレクトリを保ったままコピーする方法を教えてください。 具体的に説明すると ・aというディレクトリに、bとcというディレクトリがある。 ・bには1、2、3 という3つのディレクトリがあり、2と3が1日以内に更新されたディレクトリである。 ・cには4、5 という2つのディレクトリがあり、4が1日以内に更新されたディレクトリである。 ・1,2,3,4,5の中にはたくさんのファイルとディレクトリが含まれている。 という構成のディレクトリaがあるとして、 aのパスとコピー先のディレクトリのパスを引数や、スクリプトの中で指定し、実行すると、 ・コピー先のディレクトリに、bとcがある。 ・bには2と3があり、2にはファイル、ディレクトリがそのままコピーされている。 ・cには4があり、同じく中身はそのままコピーされている。 という結果が得られるものです。 このようなスクリプトの書き方を教えてください。

  • 16進数のデータをソートするには?

    Linux上で16進数のデータをソートしたいのですがどうすれば実現できるでしょうか? [test.txt] 11009 292f 6551 e6f6 ↓のようにソートしたい 292f 6551 e6f6 11009 手順はまず、16進数→10進数に変換してからソートでしょうか? もしそうだとしても10進数に変換するところでつまずいています。 awkのprintfでやると下記のようにエラーがでます。 (頭に0xを追加して試してもダメでした) $ awk '{printf (%d, $1)}' test.txt awk: {printf (%d, $1)} awk: ^ syntax error awk: {printf (%d, $1)} awk: ^ syntax error ↓これだと変換できるのは知っているのですが・・・。 $ printf "%d\n" 0x292f 10543 以上、よろしくお願いします。

  • スクリプトの中でのduコマンドで、Permission deniedを非表示にさせたい

    以下のコマンドを打つとPermission deniedをださずにdu検索 出来るのですが、スクリプトの中に入れて実行したくとも エラーになってしまいます。 ( du -a ~/www/logs/* ~/users/* | awk '{printf ("%.1f%s\t%s\n"),$1/1024,"M",$2}' | sort -n | tail -10 > /dev/tty ) > & /dev/null エラー 1: Syntax error: "&" unexpected 権限のない状態から指定ディレクトリの容量を検索して、 Permission deniedを表示させたくないのですが、 どうしたら、スクリプトに組み込んでいけるでしょうか。

  • バッチコマンドを作りたい

    MS-DOSでのバッチコマンドについての質問です。 パスを引数で指定して、そのパスのディレクトリ以下(サブディレクトリも含む)のファイル名を全て取得し、加工して表示するバッチを作りたいのですが・・。 例えばコマンド名を jcm をすると C:\>jcm C:\temp と入力すると(「C:\temp」は引数)、C:\temp以下(サブフォルダも含めて)にある全てのファイル名を取得し、ファイル名がA.txt,B.txtだったとすると java A.txt java B.txt のように加工して表示したのです。 バッチファイルの中身はどのように記述すればよいでしょうか?

  • 複数の条件に合致したファイルリストの作成方法を教えて下さい。

    複数の条件に合致したファイルリストの作成方法で 困っております。 Windows上のある場所に、 Directory0828  html  ┗A   ┗File001   ┗File002   ┗File003   ┗File005  ┗B   ┗File001   ┗File002   ┗File004   ┗File006  ┗C   ┗File001   ┗File003   ┗File004  img  ┗A   ┗File011   ┗File012   ┗File013   ┗File015  ┗B   ┗File011   ┗File012   ┗File014   ┗File016  ┗C   ┗File011   ┗File013   ┗File014 というディレクトリ構造とファイル群があるとします。 ※ディレクトリ名"html""img""A""B""C"は固定 ※ディレクトリは増減なし。  すなわち、第二階層はhtml,imgの2つで固定  第三階層は、それぞれに対してA,B,Cの3つで固定 ※ファイル名は、数、拡張子を含めて可変 上記を、 --------------------------------------------------- ----------- File List "Directory0828" ------------- --------------------------------------------------- 【html】 条件1)A,B,Cに全て存在するファイル名 File001 条件2)A,Bにのみ存在するファイル名 File001 File002 条件3)A,Cにのみ存在するファイル名 File001 File003 条件4)B,Cにのみ存在するファイル名 File001 File004 条件5)Aにのみ存在するファイル名 File005 条件6)Bにのみ存在するファイル名 File006 条件7)Cにのみ存在するファイル名 なし 【img】 条件1)A,B,Cに全て存在するファイル名 File011 条件2)A,Bにのみ存在するファイル名 File011 File012 条件3)A,Cにのみ存在するファイル名 File011 File013 条件4)B,Cにのみ存在するファイル名 File011 File014 条件5)Aにのみ存在するファイル名 File015 条件6)Bにのみ存在するファイル名 File016 条件7)Cにのみ存在するファイル名 なし --------------------------------------------------- という形式で Directory0828_filelist.txt という名前で作成したいのです。 上記を、プログラムの全くわからないオペレータでも 何らかの操作でミスなく行えるようにしたいのです。 ファイルリスト作成のフリーソフトやVBA、SQLなどの キーワードでいろいろ見てみたのですが、実現できそう なもの、方法が見当たりませんでした。 オペレータのPCにはExcel2003が入っているので、VBAで 実現できると一番助かります。 できれば、対象最上位親ディレクトリと同じ階層にVBA 入りのExcelファイルを置き、そのExcelファイルから、 フォーム上に該当情報(リスト対象ディレクトリ指定、 出力先パス指定)を指定後、ボタン一発で出力完了・・・ だと、とっても嬉しいです。 ただ、当方、Excel VBAは、まだ本を読み始めたばかり のド素人でして、HPに掲載されているソースのコピペ を使ってヨチヨチ歩き始めた段階です。 どなたか、お助け頂けませんでしょうか? よろしくお願い申し上げます。

  • リストファイルに一致する個数のカウントについて

    以下にリストファイルと、インプットファイルがあります。 リストファイルのそれぞれにインプットファイルの中で何個一致するかを出力させたいです。 目的にかなうawkや perlなどのスクリプトを教えてほしいです。 list.txt a b c d ・・ input.txt 1 a b c 2 a d 3 4 b c ・・ output.txt a 2 b 2 c 2 d 1 ・・

  • 【シェル】日付が最も古くサイズが小さいファイル削除

    ディレクトリ内のファイルで、日付が最も古い&(且つ)サイズが小さいものを削除するシェルを作成しようと考えています。 当初の以下のような考えをしていましたが、うまくいかないので質問しました・・・ ls -lStr(カレントディレクトリで日付が古くサイズが小さい順のつもり・・・) 上記のコマンド実行にて、 合計 100 -rwxr-xr-x 1 root root 333 2月 22 2009 java.log と表示されるのを利用し、上から2行目のファイル名を取得するためawkして『java.log』というファイル名をprintfで表示させ変数か何かに格納し、rmコマンドで削除という流れを考えていました。 よくよく考えると ・ls -lStr は本当に日付が古くサイズが小さいものでソートされているのか ・lsコマンドで表示した『2行目』という指定でファイル名の取得できるのか がよくわからなくなってしまいました。 上記の考え方よりこっちのほうが良い!やアドバイスがあれば非常に嬉しいです。 よろしくお願いしますm(__)m

  • CGI(BBS)の設置が出来ません(2)

    --------------------↓ # ログディレクトリ (フルパスだと / から) $log_dir = "."; ↑これは「/bbs.log」と入れるのでしょうか? ちなみに上記全ての書類はcgi-binで同階層です。 # 表示ファイルディレクトリ (フルパスだと / から) $htm_dir = "."; ↑これもよく分かりません。 # CGIスクリプト自身をURLで指定 $script = "http://www.●●●.ne.jp/cgi-bin/lomobbs.cgi"; ↑の様に入れましたが合っていますでしょうか? # 表示ファイル (index.html) のある「ディレクトリ」をURLで指定 $htm_url = "http://www.●●●.ne.jp/cgi-bin"; # ログファイル名 $logfile = "bbs.log"; # ロックファイル名 $lockfile = './bbs.lock'; # 過去ログのあるディレクトリ (フルパスだと / から) $past_dir = "."; # 補助プログラムのファイル名 $subfile = './bbs2.cgi'; ---------------------------- 以上、アヤシイ個所を書いてみました。 おかしな個所があれば教えてください。 ちなみに、DLしたcgiの書類名を変更したのですが、 それは何か影響はありますか? いくらやり直してもページが表示されません。

    • 締切済み
    • CGI
  • c言語のコンパイル後のエラ-について

    Unix,window98を使用しています。 #include<stdio.h> main() { doublea,b,x,y; a=1.0 ; b=2.0 ; x=a+1.0/b ; y=(a+1.0)/b ; printf(" a=%f\n b=%f\n x=%f\n y=%f\n",a,b,x,y); } を  gcc ファイル名.c    でコンパイルして、 % ./ファイル名      で実行すると、   ./ファイル名; コマンドがみつかりません。  と表示され、 % ./ファイル名.c     で実行すると、 ./ファイル名.c; アクセス権がありません と表示され、 % ./ファイル名.out    で実行すると、 ./ファイル名.out; コマンドが見つかりません。 となり、困っています。 お答えを頂ければ、嬉しいです。  

  • 他の解き方

    ディレクトリの中にアミノ酸配列が記されたファイルが5枚あります。それぞれのファイルのアミノ酸配列について疎水性指標を計算し、ファイル名とともに表示しなさい。 与えられたディレクトリ:dp18 アミノ酸配列を、疎水性指標に変換するハッシュは以下のものを用いる。 A => "1.8", V => "4.2", L => "3.8", I => "4.5", M => "1.9", W => "-0.9", F => "2.8", P => "-1.6", G => "-0.4", S => "-0.8", T => "-0.7", C => "2.5", Y => "-1.3", N => "-3.5", Q => "-3.5", K => "-3.9", R => "-4.5", H => "-3.2", D => "-3.5", E => "-3.5", ディレクトリを引数としてperlスクリプトを実行する時は、以下のように入力。 perl [スクリプト名] [ディレクトリ名] という問題を自分で解いてみたのですが、それ以外にわかりやすい方法どのような書き方があるのかを知りたいのです。わかりやすく教えてください。