我有四个文件,每个文件 10 行,如何获得如下输出

我有四个文件,每个文件 10 行,如何获得如下输出

我有4个文件。我需要检查所有文件是否具有相同的行数。

如果行数不同,我需要检测并输出,例如:

#file1 - 10 lines, file2 - 9 lines, file3 - 10 lines, file4 - 10 lines
Line are miss matched
Number of lines 10 = 9 = 10 = 10

如果它们相等,我想逐行合并文件,如下所示:

文件:

#file1
10 
12
11

#file2
Arun
kamal
babu

#file3
300
200
400

#file4
spot1
spot4
spot5

输出:

Set1
10
Arun
300
spot1

Set2
12
kamal
200
spot4

Set3
11
babu
400
spot5

我的代码:

#

id_name=`cat file2`
echo $id_name

id_list=`cat file1`
echo $id_list

#

id_count=`cat file3`
echo $id_count

id_spot=`cat spot_list`
echo $id_spot


SS=`cat id_list | wc -l`
DS=`cat id_name | wc -l`
SF=`cat id_count | wc -l`
DF=`cat id_spot | wc -l`

if [ $SS == $DS == $SF == $DF ] then

   echo " Line are matched"
   echo " Total line $SS"


   for i j in $id_list $id_name
   do
      for a b in $id_count $id_spot
      do
         k = 1
         echo " Set$k"
         $i
         $j
         $a
         $b
      done
   done

else

   echo " Line are Miss matched"
   echo " Total line $SS  = $DS = $SF = $DF"

fi

答案1

用一个非常简单的方法:

#!/usr/bin/env bash

SS=$(wc -l < file1)
DS=$(wc -l < file2)
SF=$(wc -l < file3)
DF=$(wc -l < file4)


if [[ $SS -eq $DS && $DS -eq $SF && $SF -eq $DF ]]; then 
   echo "Lines are matched"
   echo "Total number of lines: $SS"

   num=1
   while (( num <= SS )); do
      echo "Set$num"
      tail -n +$num file1 | head -n 1
      tail -n +$num file2 | head -n 1
      tail -n +$num file3 | head -n 1
      tail -n +$num file4 | head -n 1

      ((num++))
      echo
   done

else
   echo "Line are miss matched"
   echo "Number of lines $SS = $DS = $SF = $DF"
fi

它的效率不是很高,因为它调用了tail4*number_of_lines 次,但它很简单。


另一种方法是将循环替换whileawk

awk '{
   printf("\nSet%s\n", NR)
   print; 
   if( getline < "file2" )
      print
   if( getline < "file3" )
      print
   if ( getline < "file4" )
      print
}' file1

要逐行连接文件,该paste命令非常有用。您可以使用它代替循环while

paste -d$'\n' file1 file2 file3 file4

或者可能不太明显:

{ cat -n file1 ; cat -n file2 ; cat -n file3; cat -n file4; }  | sort -n  | cut -f2-

这将输出行,但不带格式(无 Set1、Set2、换行符等),因此您必须随后使用 对其进行格式化awk,例如:

awk '{ 
   if ((NR-1)%4 == 0) 
      printf("\nSet%s\n", (NR+3)/4) 
   print 
}' < <(paste -d$'\n' file1 file2 file3 file4)

最后一些注意事项:

  • 不要使用大写变量,因为它们可能与环境和内部 shell 变量冲突
  • 当您可以重定向输入时,请勿使用echo "$var" | cmd或:或cat file | cmdcmd <<< "$var"cmd < file
  • for循环中只能有一个变量名。for i in ...有效,反之则for i j in ...无效
  • 最好使用[[ ]]而不是[ ]用于测试,请参阅此回答
  • 有一个很多的方法来做到这一点
  • 您可以选择使用哪种方法,但要注意效率差异:

time在 10000 行文件上测试的结果:

#first approach
real    0m45.387s
user    0m5.904s
sys     0m3.836s
#second approach - significantly faster
real    0m0.086s
user    0m0.024s
sys     0m0.040s
#third approach - very close to second approach
real    0m0.074s
user    0m0.016s
sys     0m0.036s

答案2

您可以弄清楚如何检查每个文件的行数(提示wc:)

要获得集合的输出:

paste File{1,2,3,4} | awk -F'\t' -v OFS='\n' '{$1=$1; print "Set"NR, $0, ""}'

$1=$1用于将输入字段分隔符转换为输出字段分隔符。

相关内容