4つのファイルがあり、各ファイルには10行があります。次の出力をどのように取得できますか?

4つのファイルがあり、各ファイルには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

同じ場合は、次のようにファイルを1行ずつマージしたいと思います。

文書:

#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

4*number_of_lines 回呼び出すので、それほど効率的ではありませんがtail簡単です。


whileもう一つの方法はループを次に置き換えることですawk

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

このコマンドは、ファイルを1行ずつリンクするのに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)

いくつかの最終注意事項:

  • 環境および内部シェル変数と競合する可能性があるため、大文字変数を使用しないでください。
  • 入力をリダイレクトできる場合、またはを使用しないでくださいecho "$var" | cmd。またはcat file | cmdcmd <<< "$var"cmd < file
  • forループには変数名が1つしかありません。for i in ...有効、そうでなければfor i j in ...無効
  • [[ ]]テストするよりも使用する方が良いです[ ]。これを参照してください回答
  • 一つあるたくさんこれを行う方法
  • 使用方法を選択できますが、効率の違いに注意してください。

time10,000行のファイルでテストした結果:

#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入力フィールド区切り記号を出力フィールド区切り文字に変換するために使用されます。

関連情報