こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

行内、不要データの削除

行内、不要データの削除の方法についてお尋ねします。

05/27/2006data1data2NULLdata3151234112342
05/27/2006data1data2NULLdata4 2222data5 1 data6 text151234312344

上記の並びは、タブデリミタとなっています。
これを下記のようにしたい。

05/27/2006data1data2NULL151234112342
05/27/2006data1data2NULL151234312344

即ち、 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だけでやった方が良いと思います。
   スクリプトを教えていただけませんか?

宜しくお願いいたします。

投稿日時 - 2006-06-06 12:56:18

QNo.2198751

すぐに回答ほしいです

質問者が選んだベストアンサー

#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 を使っていいなら、
もっとマジカルなこともできますよ(笑)

投稿日時 - 2006-06-07 23:07:22

お礼

分かりやすい説明で、感激しています。
これから、shellscriptをもっと使っていこうと思います。ありがとうございました。

投稿日時 - 2006-06-09 11:02:39

このQ&Aは役に立ちましたか?

2人が「このQ&Aが役に立った」と投票しています

回答(5)

ANo.4

bashが使えるなら純粋な(外部ツールを呼び出さない)シェルスクリプトでもできると思いますが、
awkでやるなら
awk 'BEGIN {FS=OFS="\t"} {last=$NF=="" ? NF-1 : NF; print $1,$2,$3,$4,$(last-2),$(last-1),$last}'

あたりでどうでしょう?

投稿日時 - 2006-06-07 12:41:43

補足

ありがとうございます。勉強になります。
あつかましいのですが、
awk 'BEGIN {FS=OFS="\t"} {last=$NF=="" ? NF-1 : NF; print $1,$2,$3,$4,$(last-2),$(last-1),$last}'
のそれぞれの部分が何を言っているのか、結局良く理解できません。申し訳ないのですが、噛み砕いて教えていただけないでしょうか?宜しくお願いいたします。

投稿日時 - 2006-06-07 19:48:12

ANo.3

#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

投稿日時 - 2006-06-06 21:53:04

補足

小生、Perlは、それなりになれているのですが、ShellScriptはよくわかっていません。
s/[ \t]*$// これは、行末のスペースを削除。
’--- ’で繰り返し、対象は、sample.txt
次の|で引渡し、 ¥マークは何を意味しますか?
awkに続く、BEGINに対するENDはいらないのですか?
FS, OFSは、何を意味しますか?
等、誠に申し訳ないのですが、教えてください。
宜しくお願いいたします。
ありがとうございます。

投稿日時 - 2006-06-07 19:52:19

ANo.2

(1)
行末を意味するのは$です。
/(.+NULL\s).*(\d\d\s\d+\s\d+)$/ && (print "$1$2\n");
とすればいいんじゃないかと思います

投稿日時 - 2006-06-06 14:12:24

お礼

ありがとうございます。最初うまくいかなかったのですが、入力データファイルの行末にタブが入っていたためでした。
/(.+NULL\s).*(\d\d\s\d+\s\d+)\s*$/ && (print "$1$2\n");
とすることで、うまくいきました。

投稿日時 - 2006-06-06 22:47:14

ANo.1

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かもしれません。

投稿日時 - 2006-06-06 13:51:04

補足

うまくいきました。しかし、ひとつ問題がありました。
 $(NF-2),$(NF-1),$NF
これは、後ろから3つのデータを表現していると思うのですが、実行させてみると、2つのデータしか拾っていませんでした。 データを詳細に見てみると、最後の数値の後ろにタブが入っていました。これが原因で、見かけ上2つのデータと空白(最後のタブの後ろの)とで、3つのデータという理解で良いでしょうか?
タブの有り無しに関わらず、対応できるような方法ってあるでしょうか?

投稿日時 - 2006-06-06 19:14:59

あなたにオススメの質問