bash使用空替换连接多个文件(-e选项)

时间:2012-12-19 23:39:10

标签: linux bash join

我有以下代码将多个文件连接在一起。它工作正常,但我想将空值替换为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 个答案:

答案 0 :(得分:6)

另外,GNU版本的join支持-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

答案 1 :(得分:5)

文档记录不佳,但使用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。

答案 2 :(得分:1)

假设单个文件中没有重复的密钥且密钥不包含空格,则可以使用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

答案 3 :(得分: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