使用与 A B C 中的文件 B 相同的行数将多个文件合并为一个文件

cat multiple files into one using same amount of rows as file B from A B C

这是一个奇怪的问题,我一直在四处寻找,但找不到与我想做的事情相匹配的东西。

我想做的是;

文件A,文件B,文件C 5 行,3 行,2 行。

将所有文件合并到一个文件中,匹配相同数量的文件B 输出应该是

文件A,文件B,文件C 3 行,3 行,3 行。

所以在文件 A 中我必须删除两行,在文件 C 中我必须复制 1 行以便我可以匹配与文件 B 相同的行。

我想先数一下每个文件有多少行

count1=`wc -l FileA| awk '{print }'`
count2=`wc -l FileB| awk '{print }'`
count3=`wc -l FileC| awk '{print }'`

Then to do a gt then file B remove lines, else add lines.

但我迷路了,因为我不确定如何继续这样做,我从未见过有人尝试这样做。

任何人都可以给我一个想法吗?

输出应该如下图所示;

Output 谢谢。

您可以使用 head 命令 resp sed 获取文件的前 n 行。 您可以使用 echo.

生成新行

我将使用 sed,因为它允许就地编辑文件(因此您不必处理临时文件):

#!/bin/bash

fix_numlines() {
  local filename=
  local wantlines=
  local havelines=$(grep -c . "${filename}")
  head -${wantlines} "${filename}"
  if [ $havelines -lt $wantlines ]; then
    for i in $(seq $((wantlines-havelines))); do echo; done
  fi
}

lines=$(grep -c . fileB)
fix_numlines fileA ${lines}
fix_numlines fileB ${lines}
fix_numlines fileC ${lines}

如果你想要分栏输出,那就更简单了:

paste fileA fileB fileC | head -$(grep -c . fileB)

另一个用于 GNU awk 的列输出:

$ gawk  -v seed=$RANDOM -v n=2 '  # n parameter is the file index number 
BEGIN {                           # ... which defines the record count
    srand(seed)                   # random record is printed when not enough records
}
{
    a[ARGIND][c[ARGIND]=FNR]=[=10=]   # hash all data to a first
}
END {
    for(r=1;r<=c[n];r++)          # loop records
        for(f=1;f<=ARGIND;f++)    # and fields for below output
            printf "%s%s",((r in a[f])?a[f][r]:a[f][int(rand()*c[f])+1]),(f==ARGIND?ORS:OFS)
}' a b c                          # -v n=2 means the second file ie. b

输出:

a1 b1 c1
a2 b2 c2
a3 b3 c1

如果您不喜欢随机选择记录,请将 int(rand()*c[f])+1] 替换为 c[f]

$ gawk '                     # remember GNU awk only
NR==FNR {                    # count given files records
    bnr=FNR                 
    next
}
{
    print                    # output records of a b c
    if(FNR==bnr)             # ... up to bnr records
        nextfile             # and skip to next file
}
ENDFILE {                    # if you get to the end of the file
    if(bnr>FNR)              # but bnr not big enough
        for(i=FNR;i<bnr;i++) # loop some
            print            # and duplicate the last record of the file
}' b a b c                   # first the file to count then all the files to print

能否请您尝试以下。我已经将 @ 作为分隔符,您也可以根据需要更改它。

paste -d'@' file1 file2 file3 |
awk -v file2_lines="$(wc -l < file2)" '
BEGIN{
  FS=OFS="@"
}
FNR<=file2_lines{
  =?:prev_first
  =?:prev_third
  print
  prev_first=
  prev_third=
}'


以上代码的运行示例:

假设以下是 Input_file(s):

cat file1
File1_line1
File1_line2
File1_line3
File1_line4
File1_line5

cat file2
File2_line1
File2_line2
File2_line3

cat file3
File3_line1
File3_line2

当我运行以上脚本形式的代码将输出:

./script.ksh
File1_line1@File2_line1@File3_line1
File1_line2@File2_line2@File3_line2
File1_line3@File2_line3@File3_line2

要使文件具有 n 行,您可以使用以下函数(用法:toLength n file)。如果文件太长,这将省略末尾的行,如果文件太短,则重复最后一行。

toLength() {
    { head -n"" ""; yes "$(tail -n1 "")"; } | head -n""
}

要将所有文件设置为 FileB 的长度并并排显示,请使用

n="$(wc -l < FileB)"
paste <(toLength "$n" FileA) FileB <(toLength "$n" FileC) | column -ts$'\t'

正如用户所观察到的 并排输出让事情变得更加简单。但是,他们使用空行来填充短文件。以下解决方案重复最后一行以使短文件更长。

stretch() {
    cat ""
    yes "$(tail -n1 "")"
}
paste <(stretch FileA) FileB <(stretch FileC) | column -ts$'\t' |
head -n"$(wc -l < FileB)"

这是一种使用 awk 的简洁方法,我们只读取每个文件一次:

awk -v n=2 '
     BEGIN{ while(1) {
              for(i=1;i<ARGC;++i) {
                 if (b[i]=(getline tmp < ARGV[i])) a[i] = tmp
              }
              if (b[n]) for(i=1;i<ARGC;++i) print a[i] > ARGV[i]".new"
              else {break}
            }
          }'  f1 f2 f3 f4 f5 f6 

其工作方式如下:

  • 引导文件由索引 n 定义。这里我们选择引导文件为f2.
  • 我们不按顺序处理标准读取记录字段中的文件,但我们使用并行读取文件的 BEGIN 块。
  • 我们执行一个无限循环while(1),如果引导文件没有更多输入,我们将在该循环中中断。
  • 每个周期,我们使用 getline 读取每个文件的新行。如果文件i有换行,将其存入a[i],并将getline的结果置入b[i]。如果文件 i 已到达结尾,请记住最后一行。
  • b[n] 检查引导文件的结果。如果我们仍然读取一行,则将所有行打印到文件f1.newf2.new、...,否则,跳出无限循环。