アプリ版:「スタンプのみでお礼する」機能のリリースについて

cシェルの中でawkのユーザー定義関数を使う方法について教えてください。

以下の内容の入力ファイルがあったとして、
3 3 306
2 2 258
1 1 105
3列目を数値の大小に応じて、別の数値に置き換えて以下のファイル
3 3 10
2 2 9
1 1 8
を出力したいのです。
cシェルスクリプト中でawkのユーザー定義関数を使って作成したいのですが、シェルスクリプト中に関数をどこでどう定義してよいか分かりません。

cシェルスクリプトの中身は
#/bin/csh -f
gawk'{print $1,$2,symbolsize($3)}' input_data > output_data
で、以下の関数を定義したいのです。
function symbolsize(ccc){
if (ccc >= 300)
return 10 #300以上なら10を返す
if (ccc >= 200 && ccc < 300)
return 9 #200以上300未満なら9を返す
else
return 8 #それ以外なら8を返す
}

プログラミング初心者なので、なにとぞよろしくお願いします。

A 回答 (4件)

Cシェルでシェルスクリプトを書くのはお勧めできません。


Cシェルでなければだめなんでしょうか?

質問にあるようなスクリプトであれば、シェルスクリプトではなく
awkスクリプトの先頭を
#!/usr/bin/awk -f

にしたスクリプトで起動してやればいいような気がします
(awkに対する入力と出力は)与える必要がありますが。

どうしてもCシェルスクリプトで解決したいということなら

gawk '\
function symbolsize(ccc){\
if (ccc >= 300)\
return 10 #300以上なら10を返す\
if (ccc >= 200 && ccc < 300)\
return 9 #200以上300未満なら9を返す\
else\
return 8 #それ以外なら8を返す\
}\
{print $1,$2,symbolsize($3)}\
' input.txt

のように行末にバックスラッシュ(円マーク)を置いてやればできますが、
awkスクリプトの内容によってはエラーになる可能性があります。
最低でもBourn シェルを使ったスクリプトにすべきです。

参考URL:http://www.kiso.tsukuba.ac.jp/~makimura/text/nod …
    • good
    • 0
この回答へのお礼

回答ありがとうございます。うまくいきました。
Cシェルを使うことについて、リンク先も拝見しましたが、
もともと、このスクリプトは業務で使っているもので、私は、そのプログラムの
一部を書き換えているだけなので、ご指摘のように他のシェルに書き換えたりすることは
すぐには出来そうにありません。(実際は、他の処理もたくさん入っているプログラムなので
なおさら、、、)

とりあえず、cシェルで動く状態にして、ゆくゆくはBourneシェルに書き換えるか、
プログラミングの勉強もかねて、perlかrubyを使おうと思っています。

役に立ちました。どうもありがとうございました。

お礼日時:2006/12/10 02:39

awk部分は1行に書き切れる量ではないので


(本当は#1さんの回答のとおり書けなくは無いですが、
可読性が悪いので)、
awkスクリプトを別ファイルにした方が良いと思います。

(fiter.awk)
#! /usr/bin/gawk -f
{
print $1,$2,symbolsize($3)
}
function symbolsize(ccc){
if (ccc >= 300)
return 10 #300以上なら10を返す
if (ccc >= 200 && ccc < 300)
return 9 #200以上300未満なら9を返す
else
return 8 #それ以外なら8を返す
}

(filter.awkを呼び出すcshスクリプト)
#! /bin/csh -f
gawk -f filter.awk input_data > output_data


どうしても1つにまとめたいのであれば、
次のような方法があります。
(1)1つの言語にまとめる。(この場合、awkだけで書くとか、
perlの使用を検討するとか)
(2)ヒアドキュメント機能を使う。
下の例で説明すると、「<<"END_OF_FILE"」と「END_OF_FILE」で
囲まれた部分が実行時にテンポラリファイルとして
作られ、それをawkスクリプトとして使用しています。

#! /bin/csh -f
gawk -f - <<"END_OF_FILE" input_data > output_data
{
print $1,$2,symbolsize($3)
}
function symbolsize(ccc){
if (ccc >= 300)
return 10 #300以上なら10を返す
if (ccc >= 200 && ccc < 300)
return 9 #200以上300未満なら9を返す
else
return 8 #それ以外なら8を返す
}
END_OF_FILE
    • good
    • 0
この回答へのお礼

回答ありがとうございます。たしかに、awkスクリプトを別ファイルにすれば、
シンプルで分かりやすくなりますよね。
私は、この質問を投稿する前に、関数を定義する部分function symbolsize(ccc){・・・}だけを
別ファイルにしたのですが、これを
awk'{print $1,$2,symbolsize($3)}' input_data >output_data
の中にどう組み込んでいいのかわからずにいました。
最初から{print ・・・ }の部分も一緒に別ファイルにしてしまえば、
awk -f ファイル名 input_data >output_data
で動いたのですね。
関数を定義する部分だけを1つのファイルにすれば、別のスクリプトで関数を使うことも出来て
便利だと思ったのですが、無理なのでしょうか

とにかく役に立ちました。どうもありがとうございました。

お礼日時:2006/12/10 02:44

#2です。



「-f script-file」オプションは、2つ以上指定することが出来て、
その場合、それらは連結された1つのスクリプトファイルのように
扱われるので、
便利な関数の集まりを1つのスクリプトファイル(functions.awk)にして
次のように書くことが出来ます。

|gawk -f my.awk -f functions.awk input_file > output_file

本当は、個別処理(my.awk)はcshスクリプト中に直接書きたいのですが、
コマンドラインに直接書くやり方(awk '{print...')と「-f」オプションは
混在できないようです。

一応ヒアドキュメントを使って以下のように書くことは可能です。
「-f -」は標準入力(ヒアドキュメントの内容が入る)を
スクリプトファイルとして扱うことを指定します。
|gawk -f - -f functions.awk <<"END_OF_FILE" input_data > output_data
|{
| print $1,$2,symbolsize($3)
|}
|END_OF_FILE
    • good
    • 0
この回答へのお礼

プログラムファイルの前に-fをその都度付ければ、連結できるんですね。初めて知りました。

ヒアドキュメントの使い方も参考になります。「-f -」なんて
私には到底思いつきそうにないので。

十分参考になりました。ありがとうございます。

お礼日時:2006/12/14 07:02

#3の内容に関して補足です。


-f オプションの複数指定は、gawkでは問題なくできますがどのawkでもできるとは限りません。
(試せないけど Solarisのawkは怪しいと思う)

で、gawkを使ってよいという前提であれば

gawk -f functions.awk --source='print $1,$2,symbolsize($3)'

という記述ができます。
    • good
    • 0
この回答へのお礼

なるほど、gawkでは--sourceを使えば、
ファイルに記述したスクリプトと直接書いたスクリプトを連結できるわけですね。

私の使っている環境はgawkではないので、(質問文中にはgawkと書いてしまいました。すいません)
試すことができませんが、これを機にgawkをインストールしようと思います。

有用な情報、どうもありがとうございました。とても役に立ちました。

お礼日時:2006/12/14 07:23

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!