6

複数のファイルを結合する次のコードがあります。正常に動作しますが、空の値を 0 に置き換えたいので、-e "0" を使用しました。しかし、うまくいきません。何か案は?

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
4

4 に答える 4

7

余談ですが、join の GNU バージョンは-o auto. -eとは、-o人々を学習に向かわせるのに十分なフラストレーションを引き起こします。( Unix 結合を使用して外部結合ですべてのフィールドを取得する方法も参照してください)。cmhが言ったように:それは文書化されていませんが、joinを使用する場合、-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
于 2013-03-15T18:42:36.467 に答える
6

文書化は不十分ですが、オプションを使用joinする場合、-eオプションと組み合わせてのみ機能し-oます。注文文字列は、ループのたびに修正する必要があります。次のコードは、目的の出力を生成するはずです。

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 などのより強力なツールに任せる価値があるかもしれません。

于 2012-12-20T00:46:04.177 に答える
2

単一のファイルに重複するキーがなく、キーに空白が含まれていないと仮定するgawkと、ソートされたファイルのグロブを使用できます。このアプローチは、大きなファイルの場合は非常に高速であり、すべてのデータのグロブと比較して比較的少量のメモリしか使用しません。次のように実行します。

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

の内容script.awk:

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
于 2013-01-02T04:36:15.060 に答える
0

join の使用をあきらめ、別の方法でスクリプトを作成しました

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
于 2012-12-20T19:26:26.063 に答える