数百万行のテキストファイルがあり,コマンドラインから複数列に分割するための方法を探しています.
なお,何行刻みで分割するかはファイルによって違っています.
イメージとしては以下の様なtxtがあって(例:6行1列)
cat a.txt
a1
b1
c1
a2
b2
c2
これを,例えば以下の様なコマンドを叩けば3行刻みで,(3行2列)
./a.sh a.txt 3
a1 a2
b1 b2
c1 c2
と出来ると非常に幸せです.
会社のマシンで,Pythonなどが入っていないのです.
最悪の場合はCで書こうと思うのですが,
シェルスクリプト・awk, sedの範囲で,なにかいい知恵はないでしょうか.
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答4件
0
ベストアンサー
私なら量が凄いので処理にSQLを使いたいですね。
手順としては、テーブルAを作り、a.txtから一行ずつ取り出して、何行目に何があったってそしてどんなグループで結合するかを保存していきます。
テーブルA
line_no | row_value | group_no
1 |a1 |1
2 |b1 |2
3 |c1 |3
4 |a2 |1
5 |b2 |2
6 |c2 |3
最初の読み込みではgroup_no以外を保存して、UPDATEで行数に応じてgroup_noを付けるほうが全体の行数を把握してから処理できて楽かもしれません。
なお、group_noを付けずにサブクエリで頑張ればできるかもしれませんが、遅そうなのでシンプルにgroup_noをつけたほうが良いと思います。
それでSQLで呼び出してファイルに書き込めばおしまいです。(↓はMySQLでテストしました)
SQL
1SELECT group_concat( row_value order by line_no separator ' ') as newrow FROM hoge.a group by group_no order by group_no ASC;
投稿2016/06/06 10:40
総合スコア1895
0
awkです。
{ str1 = $1; getline str2 = $1; getline str3 = $1; getline str1 = str1 " " $1; getline str2 = str2 " " $1; getline str3 = str3 " " $1 print str1 print str2 print str3 }
とりあえず例示されたデータでは動くと思います。
投稿2016/06/06 09:42
総合スコア7458
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
awkの部分だけ。Windows版gwakでしか確認していません。
即興で書いたのでバグっていたらごめんなさい。
行数は決め打ちしています(lcnt = 3)。
シェルのパラメタをawkに渡してあげてください。
方針としては、
- フィールドセパレータを改行にしてガッツリ読込み
- ENDで求める結果に合わせて表示
です。力技ですが、ちょっとしたツールならばこれでいいかと思います。
一度に読込むので、行数が膨大なものには向きませんが。
awk
1BEGIN { 2 FS = "\n" 3 rc = 0 4 lcnt = 3 5} 6{ data[rc++] = $0 } 7END { 8 rcnt = int(rc / lcnt) 9 for(i = 0; i < lcnt; i++) { 10 for (j = 0; j < rcnt; j++) { 11 output = data[i + lcnt * j] 12 if (j + 1 < rcnt) { 13 printf "%s ", output 14 } 15 else { 16 printf "%s\n", output 17 } 18 } 19 } 20}
投稿2016/06/06 09:41
退会済みユーザー
総合スコア0
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/06/06 10:28
退会済みユーザー
2016/06/06 10:42
0
任意の行数で分割して列としてくっつけて行くわけですね?
ということは、戦略としては、飛ばし読みを指定した行数分繰り返すか、一旦指定行数でファイルを分割して、後でくっつけるかのどちらかになるかと思います。
指定行数でファイルを分割するAWKスクリプトは「ここ」にありましたので参照ください。
飛ばし読みだと、ファイルを指定した行数回頭からスキャンし直すことになります。スキャンの度に読み始める行を1つずつずらして指定行分飛ばして読み出せばできそうな気がします。
(例えば指定行数が3の場合、1回めのスキャンは1行目から読み始めて次は4,7,…と飛ばし読みして1行分を作って出力します。2回めのスキャンは2行目から読み始めて次は5,8,…と読み飛ばします。最後の3回めも同様です。)
なので、sedだけではちょっと難しいかと。AWKならできそうな気がします。
ただ、すいません、awkは最近全然いじってないので今すぐにはプログラムを示せません。^^;
上記のようなやり方で考えてみたらどうでしょうか?(またはawk使いのベテランが誰かいらっしゃると思うのでその人に託しますwww)
投稿2016/06/06 09:30
総合スコア3579
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/06/06 09:52
2016/06/06 10:27
2016/06/06 10:30
2016/06/06 10:33
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/06/06 10:49