人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

crontabをCSV形式で出力したいです。
まずは以下行をご覧ください。サーバのcrontabのとある1行です。
00,10,20,30,40,50 * * * * sh /home/hoge/foo.sh clean all > /dev/null 2>&1

これを以下のようにCSVデータ化したいです。
sh /home/hoge/foo.sh clean all > /dev/null 2>&1,"00,10,20,30,40,50:*","* * *"

で、これをawkでやろうとしたところ、
$ cat crontab | awk 'BEGIN{OFS=","} {print $6,$7,$8,$9,$10,$2":"$1,$3,$4,$5}'
sh,/home/hoge/foo.sh,clean,all,>,*:00,10,20,30,40,50,*,*,*
と、スクリプト指定のところはオプションまでカンマ区切りになってしまい、また10分おきに動かしているためのカンマ指定とごっちゃになってしまい、
$ cat crontab | awk 'BEGIN{OFS=","} {print $6,$7,$8,$9,$10,$2":"$1,"$3,$4,$5"}'
sh,/home/hoge/foo.sh,clean,all,>,*:00,10,20,30,40,50,$3,$4,$5
…とまぁこんな感じになってしまい上手くいきません。
awkについてはほとんど知識、コーディングしたことがないため、詰まってしまっています。
ちなみにawk縛りと言うのはありません。perlやsedでも、出来るなら手段は問わないです。
よろしくお願いいたします。

●質問者: Marin_MTB
●カテゴリ:コンピュータ インターネット
○ 状態 :終了
└ 回答数 : 1/1件

▽最新の回答へ

1 ● a-kuma3
●500ポイント ベストアンサー

awk でやると、こんな感じでしょうか。

#! /usr/bin/sh -f
crontab -l | awk '
{
 t = "\"" $1 ":" $2 "\""
 d = "\"" $3 " " $4 " " $5 "\""
 $1 = $2 = $3 = $4 = $5 = ""
 sub(/^ /, "")
 print $0 "," t "," d
}
'

時分の順番が、質問文では二種類書いてあったので、crontab に合わせて分→時としてあります。
ワンライナーでも書けますが、ちょっと苦しい感じですかね。



追記です。


$1、$2 ... は、入力行を IFS で区切ったものです。
$0 は、入力行そのものを表すのですが、$1 などを変更すると、その内容が反映されます。

$0 == $1 IFS $2 IFS $3 IFS $4 ...

という関係が、常に成り立ってます。

まず、いくつ空白が入ってるかわからない crontab のコマンドの内容を取得するためには、個数が決まっている時刻指定のところを消しちゃえば良いじゃん、ってところから入りました。

$1 = $2 = $3 = $4 = $5 = ""

が、時刻指定の最初の五つの項目を消してます。
五個目までを空文字列にすると、$0 は、その内容を反映して

$0 == " sh /home/hoge/foo.sh clean all > /dev/null 2>&1"

となってます。
空文字列五個を、OFS の空白が結合しているので、先頭に、欲しくない空白五つが付いた状態になってます。
その行頭の空白五つを切り取るのが、以下の行です。

sub(/^ /, "")

これで、コマンドの表現は手に入りました。
後は、消してしまった時刻を表す表現を、前もって別の変数に入れておくだけです。

まだ、他に聞きたいことがあれば、何なりと。
分かる範囲で答えます。


Marin_MTBさんのコメント
ありがとうございます!! 分→時は間違いです。この場合は t = "\"" $2 ":" $1 "\"" で解決ですかね。 出来れば、各行の解説が頂けると嬉しいです。 特に、 $1 = $2 = $3 = $4 = $5 = "" sub(/^ /, "") print $0 "," t "," d の部分について。$0とは?と言った所とか。 自分でawk勉強しろって話なんですが(汗)。

a-kuma3さんのコメント
>> 自分でawk勉強しろって話なんですが(汗)。 << いやいや、ぼくも先輩やネットから、いろいろ教えてもらいましたから <tt>:-)</tt> awk って、perl に比べると、教科書的なものが少ないんですよね。 というわけで、回答に追記しました。

Marin_MTBさんのコメント
ありがとうございます!! お言葉に甘えまして、出力に元のcrontabにない、任意の文字列を挿入したいです。例えばこんな感じ。 sh /home/hoge/foo.sh clean all > /dev/null 2>&1,"任意","文字列",自ホストのIPアドレス,"00,10,20,30,40,50:*","* * *"

a-kuma3さんのコメント
任意の文字列の部分は、そんなに難しくない。 自ホストのIPアドレスが、微妙。 何故って、カードが複数刺さってることがあるから。 OS 依存になっちゃうけど、linux ならこんな感じでいけるはず。 >|sh| #! /usr/bin/sh -f IP_ADDR=`env LANG=C /sbin/ifconfig | grep 'inet addr' | grep -v 127.0.0.1 | awk '{print $2;}' | cut -d: -f2` crontab -l | awk ' BEGIN { s1 = "任意" s2 = "文字列" } { t = "\"" $1 ":" $2 "\"" d = "\"" $3 " " $4 " " $5 "\"" $1 = $2 = $3 = $4 = $5 = "" sub(/^ /, "") print $0 "," s1 "," s2 "," '${IP_ADDR}' "," t "," d } ' ||<

a-kuma3さんのコメント
一応、解説。 IPアドレスの取得は、awk の範囲では取得できないので、コマンドで取得&編集して、シェルの変数に入れておく。 シェル変数の内容を awk に渡す方法はいくつかあるけれど、 >|txt| awk プログラムの文字列 ||< の、「プログラムの文字列」は、$1 とかがシェル変数の展開と解釈されてしまうので、シングルクォートでくくるのが常套なのだけれど、IPアドレスの部分はシェル変数を展開してほしいので、 >|txt| awk 'プログラムの文字列(前半)'シェル変数の展開'プログラムの文字列(後半)' ||< と、しています。

Marin_MTBさんのコメント
ありがとうございます。とても参考になります。 ちょっとawkから離れるかもですが、更に教えてください。 for文で定義された変数が表示されず、困っております。例えば、 for FILE in `ls /var/spool/cron` do echo USER=${FILE} cat /var/spool/cron/$FILE | awk '{print $1 "," '${FILE}'}' done と言う文を作成し、実行しました。 その結果、本来$FILEで定義された(例えばrootとか)が表示されるはずが表示されません。 > USER=root > */5, という感じでawkにfor文で定義された変数$FILEが反映されません。 for文の前に定義された変数についてはどうも認識するようなのですが…。 シェル変数?とは呼ばないかも知れませんが、echoでは表示されるため、一見有効そうに思われるのですが…。

a-kuma3さんのコメント
試してないので想像で書いてます。 シェル変数が展開された後は、こうなってます。 >|sh| awk '{print $1 "," root}' ||< awk は、root という文字列ではなく、root という変数を print しているのだと思います。 cat ? の行を、以下のようにしてみてください。 >|sh| cat /var/spool/cron/$FILE | awk '{print $1 "," "'${FILE}'"}' ||< 分かりにくいかもしれませんが、${FILE} を挟んでいるシングルクォートの前後にダブルクォートを入れてます。 シェル変数が展開された後に、以下のような感じに展開されるイメージです。 >|sh| awk '{print $1 "," "root"}' ||<
関連質問

●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ