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

顺便说一句,GNU 版本的 join 支持-o auto. -e并引起足够的-o挫败感,使人们转向学习 awk。(另请参阅如何使用 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 回答