質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.79%

2つのディレクトリの中身(ファイル名)を比較&マージする。

解決済

回答 4

投稿

  • 評価
  • クリップ 1
  • VIEW 3,472

score 9

超、初心者です。よろしくお願いします。

やりたい操作は2つあります。

1:2つのディレクトリには各30個のファイルがあり、この2つのディレクトリを比較して、同じ名前のファイルを取り出す。

2:同じ名前のファイルをmargeし、新しいファイルとして新しいディレクトリに書き出す

2つのファイルをmargeするには、unixのコマンドのzcat(圧縮ファイルです。)を使用するとできそうです。
例 zcat fileA.fastq fileB.fastq >fileC.fastq 

「別々のディレクトリから同じ名前のファイルを取り出す」というスクリプトが書けません(これはperlを使用したら良いのかなと思います)。また、zcat(Unixのコマンドと)とどのように組み合わせたら良いのか悩んでします。良いアイデア、スクリプトの書き方を教えていただければと思います。よろしくお願い致します。
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

+4

1:2つのディレクトリには各30個のファイルがあり、この2つのディレクトリを比較して、同じ名前のファイルを取り出す。

ファイル名に改行を含んでいたりするとダメですが comm コマンドでできます。

comm -12 <(ls aaa/) <(ls bbb/)

例えば次のように片方のディレクトリには 10 から 39 までのフィアル名が、もう片方のディレクトリには 20 から 49 までのファイルがある場合、

mkdir aaa bbb
touch aaa/{10..39}
touch bbb/{20..49}

両方のディレクトリにある 20 から 39 までのファイル名が表示されます。

comm -12 <(ls aaa/) <(ls bbb/)

comm -23 なら aaa にだけ存在するファイル名が、

comm -23 <(ls aaa/) <(ls bbb/)

comm -13 なら bbb にだけ存在するファイル名が表示されます。

comm -13 <(ls aaa/) <(ls bbb/)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/06/01 12:36

    ありがとうございました。 comm コマンド、便利ですね。試してみたところ、ファイルを取り出すことができました。これから活用したいと思います。

    キャンセル

checkベストアンサー

+1

Perlではないですが、シェルスクリプト(これはshバージョン)でこのようにできます。
マージはテキストファイルを単純に連結する前提です。

#!/bin/sh

for f in aaa/*
do
  name=`basename $f`
  if [ -f bbb/$name ]; then
    echo "merge $name"
    cat aaa/$name bbb/$name > ccc/$name
  fi
done

aaabbbを比較し、マージ結果はcccに出力します。

foraaaと同じディレクトリーのファイル名の繰り返しを行います。
basenameで名前の部分だけを取り出します。
bbbにもその名前のファイルがあれば、マージします。
マージは、zcatでなくcatを使います。
zcatは、Compressで圧縮されたファイルを展開して標準出力に流すものです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/06/01 12:35

    遅くなりました。シェルスクリプトでもできるのですね。そしてシンプルなスクリプト、ありがとうございます。試してみたのですが、if 文の後の [-f bbb/$name] でエラーが出て、-f: command not found (-fというコマンドはない)と返されてしまいます ...。どのように変更したら良いでしょうか。

    キャンセル

  • 2015/06/01 13:09

    '['が認識されていないんでしょうか? ではとりあえずifの行を
    if test -f bbb/$name; then
    に書き換えるとどうでしょうか。

    キャンセル

  • 2015/06/01 17:03

    if test -f bbb/$name; then
    と書き換えたのですけど、うまくいかなかったのですが、
    if test bbb/$name; then または、if [ bbb/$name ]; then とすると(-fを除いた)うまく動きました!
    結果オーライな気もしますが、なぜ-fを入れるとエラーが出てしまったのでしょう?
    ....ともかく、目的の作業は完了しました!

    キャンセル

  • 2015/06/01 17:11

    目的を達成されたとのことで、安心しました。

    今回はあえて環境について尋ねずに回答してしまったのが失敗だったかもしれません。
    一部のUNIXやMacOSX,Linuxでは[ -f file ]で行けると思うんですけどね。
    よろしければ下記ページを参照してみてください。
    http://shellscript.sunone.me/if_and_test.html

    キャンセル

0

とりあえず、
「別々のディレクトリから同じ名前のファイルを取り出す」というスクリプト
です。

他にもやり方があるかと思いますが、とりあえずPerlで

my @array = ( glob("dir/*"), glob("dir2/*") ); 

のdir, dir2 部分を2つの任意のディレクトリ名で修正してください。



#!/usr/bin/perl
use strict;
use warnings;
use File::Basename;

my %hash=();

my @array = ( glob("dir/*"), glob("dir2/*") );

$hash{ basename($_) }++ for( @array );


while( my ($key, $val) = each %hash )
{
        print $key,"\n" if( $val == 2 );
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/06/01 12:41

    perlのスクリプト、ありがとうございます!試してみたいのですが、whileを使った処理の部分が理解できません ..... 。解説していただけると助かります。不勉強ですみません ....。

    キャンセル

  • 2015/06/01 19:11

    %hashは、ハッシュで、ファイル名がキー($key)になっています。
    で、$valがファイル数。
    ディレクトリ1とディレクトリ2のファイル名を足しているので、
    ファイル数が2つだった場合は、ディレクトリ1とディレクトリ2で、同名のファイルが
    存在していることになります。

    キャンセル

  • 2015/06/02 13:51

    なるほど!理解できました。操作もうまくできました!

    キャンセル

0

上記のPerlを書いたものです。
アルゴリズムがちょっとわかりづらくて混乱させてしまいました。

他の方がシェルでかかれたやり方のほうが、わかりやすいかもしれませんので、
そのPerl版を書きました。(一部systemで横着してます。。)

#!/usr/bin/perl
use strict;
use warnings;
use File::Basename;

my $dir1="dir1";
my $dir2="dir2";
my $dir3="dir3";

for( glob("$dir1/*") )
{
        my $name=basename($_);
        if( -f "$dir2/$name" ) {

                my $com = "cat $dir1/$name $dir2/$name > $dir3/$name";
                print $com,"\n";
                system( $com );
        }
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/06/02 14:26

    わざわざありがとうございます!このスクリプトでもうまく動きました。最後にsystemを使うと、perl上でシェルを実行できるのですね。これも一つのやり方ですね。勉強になりました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.79%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る