2012-12-19 10 views
6

複数のファイルを一緒に結合する次のコードがあります。それはうまく動作しますが、空の値を0に置き換えたいので、-e "0"を使用しました。しかし、それは動作しません。 アイデア複数のファイルを空の置き換え(-eオプション)で結合する

for k in `ls file?` 
do 
    if [ -a final.results ] 
    then 
      join -a1 -a2 -e "0" final.results $k > tmp.res 
      mv tmp.res final.results 
    else 
      cp $k final.results 
    fi 

done 

例:

それは悪い文書化されています
file1: 
a 1 
b 2 
file2: 
a 1 
c 2 
file3: 
b 1 
d 2 

Results: 
a 1 0 1 0 
b 2 1 0 
c 2 
d 2 

expected: 
a 1 1 0 
b 2 0 1 
c 0 2 0 
d 0 0 2 
+0

'ls'の出力を解析しません。 'k for file? 'を使うだけです。します。また、ファイル名の中の特殊文字から保護するために '$ k'の拡張を引用します。 – chepner

答えて

4

が、-eオプションは-oオプションと連携して動作joinを使用。ループの周りでは、順序文字列を修正する必要があります。次のコードは、望ましい出力を生成するはずです。

i=3 
orderl='0,1.2' 
orderr=',2.2' 
for k in $(ls file?) 
do 
    if [ -a final.results ] 
    then 
      join -a1 -a2 -e "0" -o "$orderl$orderr" final.results $k > tmp.res 
      orderl="$orderl,1.$i" 
      i=$((i+1)) 
      mv tmp.res final.results 
    else 
      cp $k final.results 
    fi 
done 

ご覧のとおり、それは乱雑になり始めます。これをさらに拡張する必要がある場合は、awkやpythonのようなより肥大なツールに任せることができます。

+1

これは、スクリプトの出力である...まだ かなり右ではありません。おそらくだ B 2 2 0 1 C 2 0 2 0 D 2 0 0 2 – Amir

+1

ので、既存のfinal.resultsファイルがあります。最初に削除してみてください。私の出力はあなたが求めるものと同じです。 – cmh

+0

はい。あなたの例final.resultsを使って、このスクリプトを実行すると上記のように 'a 1 1 1 b 2 2 0 1 c 2 0 2 0 d 2 0 0 2'となります。明らかに、再実行する前にそのファイルを削除する必要があります。 – cmh

0

私は他の方法で結合を使用してあきらめ、私のスクリプトを書いた

keywords=`cat file? | awk '{print $1}' | sort | uniq | xargs` 
files=`ls file? | xargs` 
for p in $keywords 
do 
    x=`echo $p` 
    for k in $files 
    do 
    if grep -q ^$p $k 
    then 
     y=`cat $k | grep ^$p | awk '{print $2}'` 
     x=`echo $x $y` 
    else 
     echo $p $k 
     x=`echo $x 0`  
    fi 
    done 
    echo $x >> final.results 
done 
1

重複キーが単一のファイルに存在しないと仮定すると、キーは空白文字が含まれていない、あなたはgawkとのソートグロブを使用することができますファイル。この方法は、大きなファイルの場合は非常に高速で、すべてのデータのグロブに比べて比較的少量のメモリしか使用しません。 script.awk

gawk -f script.awk $(ls -v file*) 

内容::

BEGINFILE { 
    c++ 
} 

z[$1] 

$1 in a { 

    a[$1]=a[$1] FS ($2 ? $2 : "0") 
    next 
} 

{ 
    for(i=1;i<=c;i++) { 
     r = (r ? r FS : "") \ 
     (i == c ? ($2 ? $2 : "0") : "0") 
    } 

    a[$1]=r; r="" 
    b[++n]=$1 
} 

ENDFILE { 

    for (j in a) { 
     if (!(j in z)) { 
      a[j]=a[j] FS "0" 
     } 
    } 

    delete z 
} 

END { 

    for (k=1;k<=n;k++) { 
     print b[k], a[b[k]] 
    } 
} 
grep . file*

テスト入力/結果:

file1:a 1 
file1:x 
file1:b 2 
file2:a 1 
file2:c 2 
file2:g 
file3:b 1 
file3:d 2 
file5:m 6 
file5:a 4 
file6:x 
file6:m 7 
file7:x 9 
file7:c 8 

結果:脇

a 1 1 0 4 0 0 
x 0 0 0 0 0 9 
b 2 0 1 0 0 0 
c 0 2 0 0 0 8 
g 0 0 0 0 0 0 
d 0 0 2 0 0 0 
m 0 0 0 6 7 0 
4

アン、GNU版ãのように実行しますnの結合は-o autoをサポートします。 -e-oは、人々を学習awkに変えるのに十分な不満を引き起こします。 (How to get all fields in outer join with Unix join?も参照してください)。 cmhが言ったように、それは文書化されていませんが、結合を使用する場合、-eオプションは-oオプションと組み合わせてのみ機能します。

総合ソリューション:

cut -d ' ' -f1 file? | sort -u > tmp.index 
for k in file?; do join -a1 -e '0' -o '2.2' tmp.index $k > tmp.file.$k; done 
paste -d " " tmp.index tmp.file.* > final.results 
rm tmp* 

ボーナス:どのように私はgitのに複数のブランチを比較していますか?

for k in pmt atc rush; do git ls-tree -r $k | cut -c13- > ~/tmp-branch-$k; done 
cut -f2 ~/tmp-branch-* | sort -u > ~/tmp-allfiles 
for k in pmt atc rush; do join -a1 -e '0' -t$'\t' -11 -22 -o '2.2' ~/tmp-allfiles ~/tmp-branch-$k > ~/tmp-sha-$k; done 
paste -d " " ~/tmp-allfiles ~/tmp-sha-* > final.results 
egrep -v '(.{40}).\1.\1' final.results # these files are not the same everywhere 
+0

私はあなたの最初の点は、控え目なものではなく、正しい答えのほうが少ないと思います。望む効果を持つ 'join'オプションを与えます。 – WAF

+0

これを振り返ってみると、これは私の最初のGit octopus mergeの直前です。すべての違いがゼロになるまで3つのブランチを比較しました:-) –

関連する問題