6

番号順に名前が付けられた複数のファイルから5番目の列を抽出し、それらの列を順番に並べて1つの出力ファイルに貼り付けたいと思います。

ファイル名は次のようになります。

sample_problem1_part1.txt
sample_problem1_part2.txt

sample_problem2_part1.txt
sample_problem2_part2.txt

sample_problem3_part1.txt
sample_problem3_part2.txt
......

各問題ファイル(1,2,3 ...)には、2つの部分(part1、part2)があります。各ファイルの行数は同じです。コンテンツは次のようになります。

sample_problem1_part1.txt
1 1 20 20 1
1 7 21 21 2
3 1 22 22 3
1 5 23 23 4
6 1 24 24 5
2 9 25 25 6
1 0 26 26 7

sample_problem1_part2.txt
1 1 88 88 8
1 1 89 89 9
2 1 90 90 10
1 3 91 91 11
1 1 92 92 12
7 1 93 93 13
1 5 94 94 14

sample_problem2_part1.txt
1 4 330 30 a
3 4 331 31 b
1 4 332 32 c
2 4 333 33 d
1 4 334 34 e
1 4 335 35 f
9 4 336 36 g

出力は次のようになります:(problem 1 _part 1problem 1 _part 2problem 2 _part 1problem 2 _part 2problem 3 _part 1problem 3 _part 2などのシーケンス)

1 8 a ...
2 9 b ...
3 10 c ...
4 11 d ...
5 12 e ...
6 13 f ...
7 14 g ...

私が使用していたもの:

 paste sample_problem1_part1.txt sample_problem1_part2.txt > \
     sample_problem1_partall.txt
 paste sample_problem2_part1.txt sample_problem2_part2.txt > \
     sample_problem2_partall.txt
 paste sample_problem3_part1.txt sample_problem3_part2.txt > \
     sample_problem3_partall.txt

その後:

for i in `find . -name "sample_problem*_partall.txt"`
do
    l=`echo $i | sed 's/sample/extracted_col_/'`
    `awk '{print $5, $10}'  $i > $l`
done    

と:

paste extracted_col_problem1_partall.txt \
      extracted_col_problem2_partall.txt \
      extracted_col_problem3_partall.txt > \
    extracted_col_problemall_partall.txt

いくつかのファイルで問題なく動作しますが、ファイルの数が多い場合(4000を超える場合)はおかしな方法です。誰かが複数のファイルを処理できるより簡単なソリューションを手伝ってくれませんか?ありがとう!

4

5 に答える 5

8

awkソートされたファイルのグロブを使用する1つの方法は次のとおりです。

awk '{ a[FNR] = (a[FNR] ? a[FNR] FS : "") $5 } END { for(i=1;i<=FNR;i++) print a[i] }' $(ls -1v *)

結果:

1 8 a
2 9 b
3 10 c
4 11 d
5 12 e
6 13 f
7 14 g

説明:

  • 各入力ファイルの入力の各行について:

    • ファイルの行番号を、値が5列の配列に追加します。

    • (a[FNR] ? a[FNR] FS : "")は三項演算であり、配列値をレコードとして構築するために設定されます。ファイルの行番号がすでに配列にあるかどうかを尋ねるだけです。その場合は、5番目の列を追加する前に、配列値に続いてデフォルトのファイル区切り文字を追加します。それ以外の場合、行番号が配列にない場合は、何も追加せずに、5番目の列と同じにします。

  • スクリプトの最後に:

    • Cスタイルのループを使用して配列を反復処理し、各配列値を出力します。
于 2013-01-30T07:46:28.450 に答える
1

これを試してください。私のスクリプトは、すべてのファイルの行数が同じであることを前提としています。

# get number of lines
lines=$(wc -l sample_problem1_part1.txt | cut -d' ' -f1)

for ((i=1; i<=$lines; i++)); do
  for file in sample_problem*; do
    # get line number $i and delete everything except the last column
    # and then print it
    # echo -n means that no newline is appended
    echo -n $(sed -n ${i}'s%.*\ %%p' $file)" "
  done
  echo
done

これは機能します。4800ファイルの場合、AMD Athlon(tm)X2デュアルコアプロセッサBE-2400では、7行ごとに2分57.865秒かかりました。

PS:私のスクリプトの時間は、行数に比例して増加します。1000行のファイルをマージするには非常に長い時間がかかります。awkの学習を検討し、steveのスクリプトを使用する必要があります。私はそれをテストしました:4800ファイルの場合、それぞれ1000行で65秒しかかかりませんでした!

于 2013-01-30T00:40:04.193 に答える
1

わずか4000ファイルの場合、次のことができるはずです。

 find . -name sample_problem*_part*.txt | xargs paste

findが間違った順序で名前を付けている場合は、次の場所にパイプしてsortください。

 find . -name sample_problem*_part*.txt | sort ... | xargs paste
于 2013-01-30T06:14:11.323 に答える
1
# print filenames in sorted order
find -name sample\*.txt | sort |
# extract 5-th column from each file and print it on a single line
xargs -n1 -I{} sh -c '{ cut -s -d " " -f 5 $0 | tr "\n" " "; echo; }' {} |
# transpose
python transpose.py ?

ここでtranspose.py

#!/usr/bin/env python
"""Write lines from stdin as columns to stdout."""
import sys
from itertools import izip_longest

missing_value = sys.argv[1] if len(sys.argv) > 1 else '-'
for row in izip_longest(*[column.split() for column in sys.stdin],
                         fillvalue=missing_value):
    print " ".join(row)

出力

1 8 a
2 9 b
3 10 c
4 11 d
5 ? e
6 ? f
? ? g

1番目と2番目のファイルの行数が3番目のファイルよりも少ないと仮定します(欠落している値はに置き換えられます'?')。

于 2013-01-30T11:28:35.687 に答える
0

次のように、awk出力を渡して貼り付け、新しいファイルにリダイレクトできます。

貼り付け<(awk'{print $ 3}' file1)<(awk'{print $ 3}' file2)<(awk'{print $ 3}' file3)> file.txt

于 2017-04-28T19:42:58.367 に答える