- ベストアンサー
行内、不要データの削除
行内、不要データの削除の方法についてお尋ねします。 05/27/2006 data1 data2 NULL data3 15 12341 12342 05/27/2006 data1 data2 NULL data4 2222 data5 1 data6 text 15 12343 12344 上記の並びは、タブデリミタとなっています。 これを下記のようにしたい。 05/27/2006 data1 data2 NULL 15 12341 12342 05/27/2006 data1 data2 NULL 15 12343 12344 即ち、 NULL以降のdata3,data4,data5,data6等を削除し、最後の3つのデータのみを残す。 尚、上記の 15 は、たまたま、15であって、2桁の数値で変わり得ます。 これを現時点では、下記のようにしています。 ------shellscriptの中身-------------- #! /bin/bash deleteUnnecessaryInfo.pl sample.txt > test.txt ------ deleteUnnecessaryInfo.plの中身----- #! /usr/bin/perl while(<>){ /(.+NULL\s).*(\d\d\s\d+\s\d+)/ && (print "$1$2\n"); } 質問です。 (1)上記のperl scriptで、今は良さそうですが、本当は、改行マークを確認すべきだと思います。 改行マークを識別するのは、どうすればよいですか? (2)perlを呼ぶことなく、schell scriptだけでやった方が良いと思います。 スクリプトを教えていただけませんか? 宜しくお願いいたします。
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
#4 です。 awkはFSの内容にしたがって、入力のフィールド分割します。OFSは、 print 変数1, 変数2 とかしたときに、変数の内容の間に挟まります。 Perlの特殊変数でいうと $, です。 last = $NF == "" ? NF-1 : NF はなにをしているかというと、 最終フィールド($NFで表される)が空文字列であったら、NF(最終フィールドの番号)-1 を lastという変数にセットし、 空でなければNFの値をそのままセットするということしています。 つまり、これによって print $1,$2,$3,$4,$(last-2),$(last-1),$last で、一番目のフィールドから四番目のフィールド($1~$4)と 後ろから三つのフィールド($last が最後のフィールドなので、最後から 二番目と三番目はそれぞれ $(last-1)と$(last-2)になります)を 出力しているわけです。 BEGIN {} は入力を行う前に実行するものです。 入力がすべて完了した後に行うことがなければ END {} は必要ありません。 Solarisということなので nawk か /usr/xpg4/bin/awk を使っていいなら、 もっとマジカルなこともできますよ(笑)
その他の回答 (4)
- sakusaker7
- ベストアンサー率62% (800/1280)
bashが使えるなら純粋な(外部ツールを呼び出さない)シェルスクリプトでもできると思いますが、 awkでやるなら awk 'BEGIN {FS=OFS="\t"} {last=$NF=="" ? NF-1 : NF; print $1,$2,$3,$4,$(last-2),$(last-1),$last}' あたりでどうでしょう?
補足
ありがとうございます。勉強になります。 あつかましいのですが、 awk 'BEGIN {FS=OFS="\t"} {last=$NF=="" ? NF-1 : NF; print $1,$2,$3,$4,$(last-2),$(last-1),$last}' のそれぞれの部分が何を言っているのか、結局良く理解できません。申し訳ないのですが、噛み砕いて教えていただけないでしょうか?宜しくお願いいたします。
- ham_kamo
- ベストアンサー率55% (659/1197)
#1です。 行末のタブと空白を先に取り除いてawkに渡してあげればいいかと思います。 今自分の手元に環境がないので、正しく動くかは試してませんが、以下でどうでしょうか。 sed 's/[ \t]*$//' sample.txt | \ awk 'BEGIN {FS="\t";OFS="\t"} \ {print $1,$2,$3,$4,$(NF-2),$(NF-1),$NF}' > test.txt
補足
小生、Perlは、それなりになれているのですが、ShellScriptはよくわかっていません。 s/[ \t]*$// これは、行末のスペースを削除。 ’--- ’で繰り返し、対象は、sample.txt 次の|で引渡し、 ¥マークは何を意味しますか? awkに続く、BEGINに対するENDはいらないのですか? FS, OFSは、何を意味しますか? 等、誠に申し訳ないのですが、教えてください。 宜しくお願いいたします。 ありがとうございます。
- BLUEPIXY
- ベストアンサー率50% (3003/5914)
(1) 行末を意味するのは$です。 /(.+NULL\s).*(\d\d\s\d+\s\d+)$/ && (print "$1$2\n"); とすればいいんじゃないかと思います
お礼
ありがとうございます。最初うまくいかなかったのですが、入力データファイルの行末にタブが入っていたためでした。 /(.+NULL\s).*(\d\d\s\d+\s\d+)\s*$/ && (print "$1$2\n"); とすることで、うまくいきました。
- ham_kamo
- ベストアンサー率55% (659/1197)
NULLまでの項目数は4つで固定ですか? それならawkでやってみるのはいかがでしょうか。 awk 'BEGIN {FS="\t";OFS="\t"} \ {print $1,$2,$3,$4,$(NF-2),$(NF-1),$NF}' \ sample.txt > test.txt Solarisだとawkでなくてnawkかもしれません。
補足
うまくいきました。しかし、ひとつ問題がありました。 $(NF-2),$(NF-1),$NF これは、後ろから3つのデータを表現していると思うのですが、実行させてみると、2つのデータしか拾っていませんでした。 データを詳細に見てみると、最後の数値の後ろにタブが入っていました。これが原因で、見かけ上2つのデータと空白(最後のタブの後ろの)とで、3つのデータという理解で良いでしょうか? タブの有り無しに関わらず、対応できるような方法ってあるでしょうか?
お礼
分かりやすい説明で、感激しています。 これから、shellscriptをもっと使っていこうと思います。ありがとうございました。