多个文件基于file1键进行合并

时间:2017-07-14 05:39:21

标签: bash shell unix awk

我试图将多个文件与主文件密钥合并。  我的主文件是这样的

  

cat files.txt

哪个有钥匙,想比较......

1
2
3
4
5
6
7
8
9
10
11

其他输入文件

  

cat f1.txt

1 : 20
3 : 40
5 : 40
7 : 203
  

cat f2.txt

3 : 45
4 : 56
9 : 23

想要这样的输出..

   f1 f2 ....
1  20 NA
2  NA NA
3  40 45
4  56 NA
5  40 NA
6  NA NA
7  203 NA
8  NA NA
9  23 NA
10 NA NA
11 NA NA

尝试了这个,但无法打印不匹配的密钥

awk -F':' 'NF>1{a[$1] = a[$1]$2}END{for(i in a){print i""a[i]}}' files.txt *.txt
1  20
3  40 45
4  56
5  40
7  203
9  23

请有人指导我这里缺少什么吗?

6 个答案:

答案 0 :(得分:1)

复杂的GNU awk 解决方案(考虑到系统资源,将涵盖任意数量的文件):

awk 'BEGIN{ 
         PROCINFO["sorted_in"]="@ind_num_asc"; h="  "; 
         for(i=2;i<=ARGC;i++) h=(i==2)? h ARGV[i]: h OFS ARGV[i]; print h 
     }
     NR==FNR{ a[$1]; next }{ b[ARGIND][$1]=$3 }
     END{ 
         for(i in a) { 
             printf("%d",i); 
             for(j in b) printf("%s%s",OFS,(i in b[j])? b[j][i] : "NA"); print "" 
         } 
     }' files.txt *.txt

示例性输出:

  f1 f2 
1 20 NA
2 NA NA
3 40 45
4 NA 56
5 40 NA
6 NA NA
7 203 NA
8 NA NA
9 NA 23
10 NA NA
11 NA NA
  • PROCINFO["sorted_in"]="@ind_num_asc" - 排序模式(数字按升序排列)

  • for(i=2;i<=ARGC;i++) h=(i==1)? h ARGV[i]: h OFS ARGV[i] - 迭代脚本参数,收集文件名。 ARGCARGV使命令行参数可用于您的程序

答案 1 :(得分:0)

$ cat awk-file
NR==FNR{
  l=NR
  next
}
NR==FNR+l{
  split(FILENAME,f1,".")
  a[$1]=$3 
  next
}
NR==FNR+l+length(a){
  split(FILENAME,f2,".")
  bwk -v OFS='\t' -f awk-file files.txt f1.txt f2.txt[$1]=$3                                                                                                                                                 
  next
}
END{
  print "",f1[1],f2[1]
  for(i=1;i<=l;i++){
    print i,(a[i]!="")?a[i]:"NR",(b[i]!="")?b[i]:"NR"
  }
}
$ awk -v OFS='\t' -f awk-file files.txt f1.txt f2.txt 
        f1      f2
1       20      NR
2       NR      NR
3       40      45
4       NR      56
5       40      NR
6       NR      NR
7       203     NR
8       NR      NR
9       NR      23
10      NR      NR
11      NR      NR

我为你的问题修改了答案。 如果您有第3个,第4个文件(假设为第n个文件),请添加n个新块,如下所示

NR==FNR+l+length(a)+...+length(n){
  split(FILENAME,fn,".")
  n[$1]=$3
}

End区块中,

END{
  print "",f1[1],f2[1],...,fn[1]
  for(i=1;i<=l;i++){
    print i,(a[i]!="")?a[i]:"NR",(b[i]!="")?b[i]:"NR",...,(n[i]!="")?n[i]:"NR"
  }
}

答案 2 :(得分:0)

使用awk和sort -n对输出进行排序:

$ awk -F" *: *" '
NR==FNR {
    a[$1]; next }
FNR==1 {
    for(i in a)
        a[i]=a[i] " NA"
    h=h OFS FILENAME
}
{
    match(a[$1]," NA")
    a[$1]=substr(a[$1],1,RSTART-1) OFS $2 substr(a[$1],RSTART+RLENGTH)
} 
END { 
    print h
    for(i in a) 
        print i a[i]
}' files f1 f2 |sort -n
 f1 f2
1 20 NA
2 NA NA
3 40 45
4 56 NA
5 40 NA
6 NA NA
7 203 NA
8 NA NA
9 23 NA
10 NA NA
11 NA NA

陷阱:1。sort在某些情况下会因标题而失败。 2.由于NA已替换为值$2,因此您的数据不能包含NA个起始字符串。替换/ NA( |$)/可能会避免这种情况,但可能会导致更多的代码检查,因此请仔细选择NA。 :d

修改

运行它,例如,四个文件:

$ awk '...' files f1 f2 f1 f2 | sort -n
1 20 20 NA NA
2 NA NA NA NA
3 40 45 40 45
4 56 56 NA NA
5 40 40 NA NA
6 NA NA NA NA
7 203 203 NA NA
8 NA NA NA NA
9 23 23 NA NA
10 NA NA NA NA
11 NA NA NA NA

答案 3 :(得分:0)

$ cat tst.awk
ARGIND < (ARGC-1) { map[ARGIND,$1] = $NF; next }
FNR==1 {
    printf "%-2s", ""
    for (fileNr=1; fileNr<ARGIND; fileNr++) {
        fileName = ARGV[fileNr]
        sub(/\.txt$/,"",fileName)
        printf "%s%s", OFS, fileName
    }
    print ""
}
{
    printf "%-2s", $1
    for (fileNr=1; fileNr<ARGIND; fileNr++) {
        printf "%s%s", OFS, ((fileNr,$1) in map ? map[fileNr,$1] : "NA")
    }
    print ""
}

$ awk -f tst.awk f1.txt f2.txt files.txt
   f1 f2
1  20 NA
2  NA NA
3  40 45
4  NA 56
5  40 NA
6  NA NA
7  203 NA
8  NA NA
9  NA 23
10 NA NA
11 NA NA

以上使用GNU awk进行ARGIND,其他awks只在脚本开头添加一行FNR==1{ARGIND++}

答案 4 :(得分:-1)

请使用以下脚本进行处理。 FILESPATH包含输入文件列表(f1.txt,f2.txt ...)。 INPUT有输入文件(files.txt)。

script.sh

var http = require('http'),
url = require('url'),
fs = require('fs');
var express = require('express')
, app = module.exports = express();
 var router=express.Router();
//var fs = require('fs');
// string generated by canvas.toDataURL()
router.get('/', function(req, res, next){
var img = 
"Right_9660009901_20170707_172902_1023927555.jpg";
// strip off the data: url prefix to get just the base64-encoded bytes
var fs = require("fs");
fs.writeFile("image.jpg", new Buffer(img, "base64"), function(err) {});
 });

====== 您可以使用printf而不是echo来更好地格式化输出。

答案 5 :(得分:-1)

这可以通过简单的循环和echo语句来完成。

#!/bin/bash
NA=" NA"
i=0

#print header module start

header[i]=" "
for file in `ls f[0-9].txt`;
do
first_part=`echo $file|cut -d. -f1`
i=$i+1
header[i]=$first_part
done
echo ${header[@]}

#print header module end


#print elements start
for element in `cat files.txt`;
do

 var=$element
        for file in `ls f[0-9].txt`;
        do
                var1=`grep -w ${element} $file`
                 if [[ ! -z $var1 ]] ; then
                 field2=`echo $var1|cut -d":" -f2`
                 var="$var$field2"
                 else
                 var="$var$NA"
                 fi
        done
                 echo $var

done
#print elements end