【问题标题】:Merge multiple files to a single file including unmatched lines in shell将多个文件合并到一个文件中,包括 shell 中不匹配的行
【发布时间】:2019-12-18 16:26:24
【问题描述】:

文件1.log

207.46.13.90  37556
157.55.39.51  34268
40.77.167.109 21824
157.55.39.253 19683

文件2.log

207.46.13.90  62343
157.55.39.51  58451
157.55.39.200 37675
40.77.167.109 21824

文件3.log

207.46.13.90  85343
157.55.39.51  59876
157.55.39.200 37675
157.55.39.253 19683

下面应该是history.log

207.46.13.90    37556   62343   85343
157.55.39.51    34268   58451   59876
157.55.39.200   -----   37675   37675
40.77.167.109   21824   21824   -----
157.55.39.253   19683   -----   19683

使用加入不起作用 - 我可以按照 Ravinder 在另一个线程中的建议获得 2 个文件:Join two files including unmatched lines in Shell

另外,在下一次运行中,我会将另一个 file4.log 添加到说 history.log 作为第 4 列。提前致谢。

【问题讨论】:

    标签: linux shell join awk


    【解决方案1】:

    您可以使用这个gnu awk 来组合具有与第一列值相同的键的多个文件:

    awk -v OFS='\t' '{
       a[$1][ARGIND] = $2
    }
    END {
       for (i in a) {
          printf "%s", i
          for (j=1; j<ARGC; j++)
             printf "%s", OFS (j in a[i] ? a[i][j] : "-----")
          print ""
       }
    }' File*.log
    

    207.46.13.90    37556   62343   85343
    40.77.167.109   21824   21824   -----
    157.55.39.51    34268   58451   59876
    157.55.39.253   19683   -----   19683
    157.55.39.200   -----   37675   37675
    

    【讨论】:

      【解决方案2】:

      请您尝试以下操作。这也应该适用于 3 个以上的 Input_file(尽管仅使用 OP 的示例 3 Input_file 进行了测试,但应该可以使用)。

      awk '
      FNR==1{
        count++
      }
      {
        a[$1]
        b[count,$1]=$2
      }
      END{
        for(j in a){
          for(i=1;i<=count;i++){
            printf("%s%s%s",i==1?j OFS:"",b[i,j]?b[i,j]:" ----- ",i==count?ORS:OFS)
          }
        }
      }
      '  Input_file1  Input_file2  Input_file3 | column -t
      

      输出如下。

      207.46.13.90   37556  62343  85343
      40.77.167.109  21824  21824  -----
      157.55.39.51   34268  58451  59876
      157.55.39.253  19683  -----  19683
      157.55.39.200  -----  37675  37675
      

      说明:在此添加对上述代码的详细说明。

      awk '                                                                              ##Starting awk program from here.
      FNR==1{                                                                            ##Checking condition if this is first line then do following.
        count++                                                                          ##Creating a variable count whose value is increasing each time FNR==1 for each Input_file first line.
      }
      {
        a[$1]                                                                            ##Creating an array named a whose index is $1 first field of current line for Input_file(s).
        b[count,$1]=$2                                                                   ##Creating an array named b whose index is count,$1 and value is $2 of current line.
      }
      END{                                                                               ##Starting END BLOCK for this awk program here.
        for(j in a){                                                                     ##Looping through array a all elements from here.
          for(i=1;i<=count;i++){                                                         ##Running a for loop from i=1 till value of count.
            printf("%s%s%s",i==1?j OFS:"",b[i,j]?b[i,j]:" ----- ",i==count?ORS:OFS)      ##Using printf statement where first condition its checking is i==1 TRUE then print j OFS OR print NULL, checking condition if element b[i,j] is NOT NULL then print its value else print NULL. Final condition is if i==count then print new line else print space.
          }                                                                              ##Closing BLOCK for, for loop of i=1 to i<=count.
        }                                                                                ##Closing BLLOCK for, for loop (j in a) here.
      }                                                                                  ##Closing BLOCK for END BLOCK of this awk program.
      '  Input_file1  Input_file2  Input_file3 | column -t                               ##Mentioning Input_file names here and sending its output to column -t command to get correct spaces in output.
      

      【讨论】:

      • 感谢代码 - 抱歉,我不清楚这个问题。我不会一次合并所有 3 个文件。我将附加 history.log + 1 个新生成的文件。以便它只添加列,并且第四次我需要将 count 添加到 history.log 的第四列
      • @user2170023,所以你的意思是你的文件数量没有设置,它们会不断增加对吗?
      • 正确,每次运行我都会在 history.log 中添加一个新文件
      • @user2170023,那么这段代码应该可以解决这个问题,你能不能用 3 个文件然后 4 个等尝试一次,然后让我知道?
      • ' history.log iplog_new.log | column -t >> history.log
      【解决方案3】:

      使用join,这是一个两步过程:请注意,join 需要对其输入进行词法排序

      1. 首先你需要加入前两个文件:

        join -a 1 -a 2 -e "-----" -o "0,1.2,2.2" <(sort File1.log) <(sort File2.log)
        
        157.55.39.200 ----- 37675
        157.55.39.253 19683 -----
        157.55.39.51 34268 58451
        207.46.13.90 37556 62343
        40.77.167.109 21824 21824
        
      2. 然后将 该输出 与文件 3 连接:

        join -a 1 -a 2 -e "-----" -o "0,1.2,1.3,2.2" \
          <( join -a 1 -a 2 -e "-----" -o "0,1.2,2.2" <(sort File1.log) <(sort File2.log) ) \
          <(sort File3.log)
        
        157.55.39.200 ----- 37675 37675
        157.55.39.253 19683 ----- 19683
        157.55.39.51 34268 58451 59876
        207.46.13.90 37556 62343 85343
        40.77.167.109 21824 21824 -----
        
      3. 如果需要,可以使用column 整理输出:

        join -a 1 -a 2 -e "-----" -o "0,1.2,1.3,2.2" \
          <( join -a 1 -a 2 -e "-----" -o "0,1.2,2.2" <(sort File1.log) <(sort File2.log) ) \
          <(sort File3.log) \
          | column -t
        
        157.55.39.200  -----  37675  37675
        157.55.39.253  19683  -----  19683
        157.55.39.51   34268  58451  59876
        207.46.13.90   37556  62343  85343
        40.77.167.109  21824  21824  -----
        

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-11-06
        • 2017-07-02
        • 2020-01-15
        • 1970-01-01
        • 2016-06-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多