• ベストアンサー

シェルスクリプトの中のawkユーザー定義関数

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を返す } プログラミング初心者なので、なにとぞよろしくお願いします。

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

  • ベストアンサー
  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.4

#3の内容に関して補足です。 -f オプションの複数指定は、gawkでは問題なくできますがどのawkでもできるとは限りません。 (試せないけど Solarisのawkは怪しいと思う) で、gawkを使ってよいという前提であれば gawk -f functions.awk --source='print $1,$2,symbolsize($3)' という記述ができます。

takenobu
質問者

お礼

なるほど、gawkでは--sourceを使えば、 ファイルに記述したスクリプトと直接書いたスクリプトを連結できるわけですね。 私の使っている環境はgawkではないので、(質問文中にはgawkと書いてしまいました。すいません) 試すことができませんが、これを機にgawkをインストールしようと思います。 有用な情報、どうもありがとうございました。とても役に立ちました。

その他の回答 (3)

回答No.3

#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

takenobu
質問者

お礼

プログラムファイルの前に-fをその都度付ければ、連結できるんですね。初めて知りました。 ヒアドキュメントの使い方も参考になります。「-f -」なんて 私には到底思いつきそうにないので。 十分参考になりました。ありがとうございます。

回答No.2

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

takenobu
質問者

お礼

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

  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.1

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/node239.html
takenobu
質問者

お礼

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

関連するQ&A

  • 権限の違うシェルスクリプトの実行

    3つのシェルスクリプトがあります。 ●root権限で実行  aaa.csh ●ユーザ指定権限で実行 bbb.csh ●root権限で実行 ccc.csh この3つのシェルスクリプトはaaa.csh →bbb.csh →ccc.cshの順番でバッチ処理として cronに設定したいのですが、 権限が違うのでroot権限のcrontabとユーザ指定のcrontabに それぞれ設定しなくてはいけません。 あまりスマートではないかと思い、 何かよい方法はないかと質問させて頂きました。 3つのシェルスクリプト1つシェルスクリプトにまとめてroot権限のcrontabに設定してしまう方法とかどうでしょうか? ちなみにスクリプトの処理の内容は単純なファイルコピーなどです。 意味分かりますでしょうか? よろしくお願いします。

  • 今、awkを使ったシェルスクリプトを作っています。

    今、awkを使ったシェルスクリプトを作っています。 aaa bbb ccc ddd ee ff gggg hhh といったファイルから、 bbb,ccc ff,gggg を取り出したいと思っています。 そこで、以下のコマンドをwhileでまわして、$iを増加させることにより、 ファイルを一行ずつ読み取り、目的の列を取り出したく思っています。 A=`cat sample.txt|awk 'NR == $i {print NR, $2;}'` B=`cat sample.txt|awk 'NR == $i {print NR, $3;}'` ところが、awkコマンドの中の$iがシングルクォーテーションでくくられているので、 変数展開されなくて困っています。 何かよい方法があればご教授いただけますでしょうか?

  • シェルスクリプトの切り替え?

    シェルには種類がありユーザーはそれを切り替えることによって好みのシェルを自由に選択することが出来る。 というのはわかりました。 が、シェルスクリプトを記述して実行する場合はどうなんでしょう。 bornシェルで記述したシェルスクリプトをcshから実行できるのでしょうか。 実行者とスクリプト記述者が同じシェル環境で操作しないといけないのかと思い質問しています。 ひょっとして意味のわからない質問かも知れませんがお願いします。

  • シェルスクリプトで、空白(スペース)を含む変数をawkに渡したいのです

    シェルスクリプトで、空白(スペース)を含む変数をawkに渡したいのですが、どうしたらいいでしょうか? 例えば、以下のようなtest.shというファイルを作ったとします。 --------------- #!/bin/sh AAA="x y" echo "" | awk '{print $AAA}' -------------- としたとき、$AAAが正常に出力できません。(なお、echo "" は、awkを走らせる為の単なるダミーです。) printの部分を ・awk '{print '$AAA'}' ・awk '{print "'$AAA'"}' などともしてみましたが、ダメでした。どのようにすればうまくいくでしょうか?

  • シェルスクリプト

    こんばんわ。最近Tru64でシェルスクリプトを書いています。そこで質問ですが、 前の実行コマンドが正常に終了したら次のコマンドが実行されるスクリプトはどのように書けばよいのでしょうか? if文で可能なのでしょうか? またkillコマンドをawkで kill psID OK?(y/n) と表示させyを押せばkillするようにするにはどのようにすればよいですか? 例のように表示させることはawkでできるのですがどうしたらy入力後killできるのかわかりません。 これもif文を使わなければだめなのでしょうか? よろしくお願いします。

  • シェルスクリプトの書き方

    すみません、シェル初心者なのですが、急を用してまして質問させて頂きました。 シェルスクリプトで コマンドを実行する前に他のユーザにスイッチしてから 実行するというのを実現したいのですが・・・ #!/bin/csh コマンド1 コマンド2 ・・・ とコマンド1の前に su コマンドを実行させたいのですが、 パスワードを入力する際、対話式なので どう書いてよいか分かりません。 よろしくお願いします。

  • awk内でsystem関数を使用しfunction

    環境:AIX5.2 シェル:ksh を使用してシェルを作成しています。 awk内でsystem関数を使用しfunctionを呼び出す事は可能でしょうか? 実現したい内容は以下です。 ・awk内で同一シェルに記述されたfunctionを呼び出す ・functionを呼び出す際には引数を渡す 記述イメージ的に以下のような感じでスクリプトに記述していますが、 system関数内で呼び出そうとしているfunctionをfunctionとして 認識できないのでは??っという疑問を持ち始めてます。 function hoge{  HOGE=$1 echo ${HOGE} } awk'{ BEGIN{FS=":"} system(hoge AAA) }'

  • ユーザー定義関数について

    ここで良いのかわかりませんが質問します。 現在、ExcelVBAをすこしかじりました。 ユーザー定義関数を作りましたが、第三者に簡単にわかるようにしたいと思います。fxボタンを押せばなんとなく第三者でもわかりそうですが、ボタンの存在を知らない人はわからないと思いました。 ワークシート上では直接関数を打てば、直下にコメントのようなスタイルでどの数値を入れればよいか出てくると思います。 =round( と打てば =round( (数値,桁数) というように出てくるのですが、ユーザー定義関数でこのようなことはできるのでしょうか? これが出来る出来ないでは第三者への進め方が大きく違ってきます。 教えてgooはもちろんいろいろ調べましたがわかりません。 何卒ご指導お願いします。

  • シェルスクリプトの中であるプログラムにシグナルを送りたいとき

    こんにちわ, 今シェルスクリプトの学習をしています。 シェルスクリプトのなかであるプログラムにSIGINTを送るシェルスクリプトを作るにはどうすればいいでしょうか。 たとえば, ./hogeというCプログラムがあり,その中でsignal関数を用いてSIGINTを捕らえるようなプログラムがなされているとき, シェルスクリプトで #!/bin/sh ./hoge & PID=$$ sleep 2 kill SIGINT $PID だと,$$にはこのシェル自体のPIDが返ってきているので,うまくいきません。 なんとか,./hogeをうごかし,その後何秒かあとにSIGNALを送るようなシェルスクリプトを作りたいのですが,どうすればいいでしょうか。 Cでforkさせて外部呼出しによって送るしかないのでしょうか。 よろしくお願いします。

  • ユーザー定義関数の処理

    エラーメッセージに関する以下の関数はどのような処理をする関数ですか? 自分なりに解釈したものを//で書いています。 // エラーがセットされているときは、$errorsを返す // もしセッション変数にエラーがないときは、空の配列を返す function get_errors(){ // セッション変数にエラーがセットされているときは$errorsを以下のように定義する $errors = get_session('__errors'); if($errors === ''){ return array(); } // もしセッション変数にユーザー名($name)がセットされているなら、セッション情報を返す // セットされていないときは空文字を返す function get_session($name){ if(isset($_SESSION[$name]) === true){ return $_SESSION[$name]; }; return ''; } // $nameと$valueを受け取り、セッション情報(ユーザー名)を$valueと定義する function set_session($name, $value){ $_SESSION[$name] = $value; }

    • ベストアンサー
    • PHP