• 締切済み

[awk]2つのファイルを参照して1つのファイルに出力する方法

最近プログラミング(シェル、awk)を始めた者です。 かなり大まかなものは作れるようになったのですが、急遽、大規模なデータ整理を行わないといけなくなってしまったため、皆さんの知恵を貸していただきたく質問いたしましたm(_ _)m 以下に示すような2つのファイルがあります。 (file1)         (file2) 1 6           1  1  2  10 11 2 3           2  3  5  7  8 3 5           3  6  2  12 13 4 1           4  9  4  5  19 5 2           5  10 19 1  5 6 4           6  4  8  2  9 file1を上から1行ずつ順に読んでいき、2列目の値と同じものをfile2の1列目から探します。合致したところで、file2の合致した行の2列目以降を行番号を付けて表示するというものです。 (「file1の2列目の値=file2の1列目の値」を探し、file2の合致行の値を出力。) 上記ファイルですと、結果的に 1  4  8  2  9 2  6  2  12 13 3  10 19 1  5 4  1  2  10 11 5  3  5  7  8 6  9  4  5  19 という具合になります。 2つのファイルの行数は同じではなく、また、両ファイルとも1列目が行番号というだけで、他の列の値に規則性はありません。 file2の行数は100万以上の大規模なものになります。 自分が作ったものを掲載できればよかったのですが、あいにく会社のPC内にありまして、持ち出しできないため、掲載できません。 動作環境はLinux(RedHat)になります。 他のプログラミング言語についてはまだ分からないため、awkもしくはシェルでお願いいたします。

みんなの回答

  • nza49739
  • ベストアンサー率46% (29/62)
回答No.5

ごめんなさい、一部間違いがありました。 誤: tail -1 | head -(ここに取り出した番号を入れる) ↓ 正: head -(ここに取り出した番号を入れる) | tail -1 パイプの順序が逆でした。お詫びして訂正します。

  • notnot
  • ベストアンサー率47% (4848/10262)
回答No.4

file1の行数は少ないということでいいですか? 最初にfile1を配列に読み込んでしまって、file2を読むたびにその配列をチェックします。 BEGIN{n=1 while(getline < "file1"){ A[n]=$1; B[n]=$2; n++;} } {K=$1; $1=""; for(i in B){if(K==B[i]){A[i]=A[i] $0;}} } END{ for(i=1;i<n;i++) print A[i]; } これを script というファイル名で保存して、 awk -f script file2

tomo0757
質問者

お礼

詳しくありがとうございますm(_ _)m またも説明不足だったのですが、file1はfile2よりも少ないんですけど、それでも数十万行あります(^-^; 現在の方法だと、「file1を読むたびにfile2を読む」というループになってしまっていたので、長時間必要だったのだと思います さっそく試してみます!! ありがとうございますm(_ _)m

  • nza49739
  • ベストアンサー率46% (29/62)
回答No.3

行単位のデータを書き込んでいくだけの処理のようですので、awkをつかわなくてもいけそうですね。 for ループでfile1のデータを順々に取り出して、tail -1 | head -(ここに取り出した番号を入れる)で行が取り出せるので、後はcatコマンドで合成 という方法ですね。

tomo0757
質問者

お礼

なるほど そういう方法もあるんですね!! ハードにはそこそこ強いんですけど、ソフトはまったくなので(^-^; 勉強になりますm(_ _)m

  • osamuy
  • ベストアンサー率42% (1231/2878)
回答No.2

スピードを求めなくて良いなら、 >両ファイルとも1列目が行番号 を利用して、file1の2列目が示す数字の行をfile2から抽出 awkならNR==なんとか、sedなら、なんとかpで出力。 ――というシェルスクリプトでいけそうな。 まあ、file2の行数より大きい値がfile1で指定されてた場合どういう振る舞いをすればよいのかとか仕様が不明確なところがありますが。 スピードを求めるなら、1000万行全部オンメモリに読み込んで、バイナリサーチするか、配列で添え字アクセスするか。

tomo0757
質問者

お礼

さっそくありがとうございますm(_ _)m >file2の行数より大きい値がfile1で指定されてた場合どういう振る舞いをすればよいのかとか 説明不足でした… file1の値がfile2の行数より大きくなることはありませんし、スピードも要求されます かなり欲張りな内容ですね… ハードはサーバ(Xeon系がItanium系CPU)なので、処理速度には問題ないと思います ちなみに、自分でも簡単なもの(if構文でループさせる回りくどいもの)を作ったのですが、200万行の処理に2日かかってしまいまして… NRの存在を忘れてました(^-^; 明日にでも試してみようと思います!! ありがとうございますm(_ _)m

回答No.1

> file2の行数は100万以上の大規模なものになります。 SQLiteなどの簡単なデータベースもあるので file2 をデータベースに入れて処理するのが簡単と思いますが・・・ データベース化しないなら file2の1列目をキーにした連想配列を作成するのがベタなコーディングだと思います。

tomo0757
質問者

お礼

さっそく回答ありがとうございますm(_ _)m そのようにできればいいのですが、この前にも後にも同じファイルを使った処理があるので、できたらそれらも含めた一つのプログラムとしたかったので…

関連するQ&A

  • awkについて

    awkの勉強を始めました。入力ファイルから特定の行を抜き出し、平均値を求めようとしています。しかし、FNRとはファイルの全行のようで、FNRで割ると正しい値になりません。特定の文字($8="abc")の行だけ抜き出しているので行数は全体より小さいのですが、抜き出した行数で割るにはどうすればよいのでしょうか。

  • awk '{print $1}' file をもっと簡単に書きたい

    awkで最も頻繁に使うのが、fileのN列目だけを抜き取ってくるという使い方なんですが ↓ awk '{print $N}' file Nとfileという2つの引数しか使わないのでこれを   my_awk N file  といった具合に間単に使える my_awk シェルを作りたいんですが、$のあたりがうまくかけません、どう直せばいいでしょうか?↓ #!/bin/csh awk '{print $$1}' $2

  • awkで複数ファイルのある列を抽出し出力したい

    awkプログラミングの初心者です。 今、複数ファイル(1000ファイル)から、それぞれある列(すべて同じ列番号)のデータを抜き出して、1つのファイルに出力したいと考えています。 具体的には、1列目に共通項、2列目以降に1000ファイル分の抽出された列を、合計1001列となるような1つのファイルとして出力したいと考えております。 awkを使って出力するには、どのようなスクリプトを作ればよいか教えていただけませんでしょうか。 <イメージ> 元となるファイル(例えば下記のように3ファイル、実際には1000ファイル)があります。 file1.txt: 1  10 2  15 3  17 :  : 1000  25 file2.txt: 1  5 2  40 3  22 :  : 1000  17 file3.txt: 1  9 2  20 3  16 :  : 1000  32 出力後のファイルイメージ: 1  10  5  9 2  15  40  20 3  17  22  16 :  :  :  : 1000  25  17  32 ちなみに、自分で作成したawkスクリプト(下記)では、上記出力後のイメージとは異なり、 縦にデータが結合されてしまいました。 awk `{print $2}` ./file*.txt > Output.txt 出力後のファイル: 10 15 17 : 25 5 40 :

  • awk外で宣言した変数の参照

    kshを使用して、以下のようなシェルを作成しています。 しかしawk内で$iと$iiが参照出来てない様子です。 どのようにすれば参照できますでしょうか。 ■シェルの中身 #/usr/bin/ksh for i in `cat /tmp/hoge |awk -F : '{ print $3 }' | sort | uniq -d` do if [ $i != "" ]; then for ii in `cat /tmp/hoge` do echo $ii |awk -F ":" '{ if ( $3 -eq $i ) print $ii }' done fi done ■エラー awk: 0602-562 フィールド $() が正しくありません。 入力の行番号は 1 です。 ソースの行番号は 1 です。

  • awkで可変文字列をマッチング

    シェルなどでawkを使う際に、シェルの引数として渡された文字列をawkに渡し、それを条件にマッチングをかけたいのですが、どうしたら良いのでしょうか?(まあ、素直にgrepを使えばいいのですが・・・) 例えば、 cat foo.txt | awk '{if ($2 == ptn) print}' ptn=$<シェルの引数> とかやれば、2番目のフィールドに完全に一致する行が抽出できるのですが、 cat foo.txt | awk '/ptn/ {print}' ptn=$<シェルの引数> とかやっても、"ptn"という文字列をマッチングしてしまうので、うまくいきません。どの位置に出現するかわからないけど、シェルの引数で指定された文字列が含まれている行だけを出力したい場合、どうしたらよいのでしょう・・・。

  • awkで列指定をして削除

    awkかsedを利用して以下のファイルを処理したいです。 1 2 3 4 5 2 1 3 4 5 1 2 3 4 5 3 1 3 4 5 一列目の値が1の行のみ削除したいです。 2 1 3 4 5 3 1 3 4 5 こんな感じです。 実際に処理するファイルは膨大な行数ががあるためprintでは難しいです。 よろしくお願いします。

  • awkでファイルから読み込んだ値を、演算させるにはどうしたら良いですか

    awkでファイルから読み込んだ値を、演算させるにはどうしたら良いですか。 ファイル(hoge.txt)の内容は、次の通り(全4行) 123 456 50 20 これを、bashスクリプトで計算させます。 FF=`cat hoge.txt | awk 'BEGIN {x=$2;printf ("%s, %s", (148+x*0.05), x);}'` echo "答え = ${FF}" このときの$2の値は、50です。但し、文字列として扱われているようです。 xの値を、数値として代入され、四則演算をさせるにはどうしたら良いですか? 以上、よろしくお願いします。

  • UNIX awkコマンド

    シェルスクリプトで、awkをつかって計算を行いたいのですが、 例えば、 file1 5040 というものが入っていたとして、 1列目の5と3列目の4を抽出して 5-4をさせて、 新しいファイルに、1という結果を保存したい場合、 どのようにしたらよいのでしょうか?? awk '{printf("%s\n",substr(0,1-3,1))} file1 > newfile でできると思ったのですができませんでした。 わかる方いましたら教えてください。

  • awkでn行目までを1行に入れたい

    awkを使ってこの問題を解決できるかどうか教えてください。 次のようなファイルがあるとします。 各行には第1フィールドしか値がありません。 $cat aaa 11111 22222 33333 44444 55555 66666 このファイルを次のように並べ替えたいです。 11111 22222 33333 44444 55555 66666 3行目までの値を1行目に入れ、 次の4行目から6行目までの値を2行目に入れていきたいです。 使用する環境は、solaris,Linuxの混在環境です。 awkで実現できるのではないかと考えていますが、もしできなければその他の方法を教えて頂ければありがたいです。 宜しくお願いします。

  • awk in csh

    cshスクリプトの中で、awkと連動させたプログラムを書こうとしています。 以下の様なテーブルファイル(hoge.txt)があると想定してください。 1 0.01 0.52 3.23 ..... 2 0.22 9.34 8.22 ..... 3 0.44 0.68 3.81 ..... ... (列も行も揃っている数値だけのテーブル) 例えば、変数hogeに第2行、第2列の数値(文字列)0.22を代入する際、 シェルスクリプト内部で、 @ hoge = `awk 'NR==2' {print $2} hoge.txt` としましたが、$2をスクリプトに与えられた2番目の引数だと解釈して、 うまく動作しません。 試しに$2 -> \$2に変換してみましたが、ダメでした。 (\の後に改行がないというエラーが出ました) 第i列目,j行目の文字列を取り出すにはどのようにすれば良いでしょうか。

専門家に質問してみよう