コマンドやスクリプトなど、コードを管理して実行もできる自作FileMaker書類 CodeManager.fmp12 の利用と仕組みについて。その2。今回は、コマンドライン命令文を do shell script に変換する計算式について。
前の記事 Macで実行可能なFileMakerコード管理 CodeManager v2 の続きです。
コマンドラインを do shell script に変換
フィールド CodeDoScript が本ファイルの要のひとつ、コードを実行できる形に変換する計算フィールドです。変換テンプレートを使って do shell script に変換します。
変換テンプレートはこのような簡単な一文です。

CodeDoScript フィールドの計算式は、書かれたコードをコマンド化する計算式ということですね。
CodeDoScript フィールドの計算式
$COMMAND を置き換える計算式で以下ですが。現状、このようになっています。ざっくり載せます。
Let ( [ code = CodeRun::CodeTemp ; /* テンプレート。念のために二つ用意している. 現状では DoShellScript を使用 */ template_base = Template_DoScript; template_shell = Template_DoShellScript; /* テンプレートを選択 */ template = template_shell ; /* pass */ password = password ; /* do shell script のみ: 外部ツールにパスを加える */ comPath = If ( LeftWords ( code ; 1 ) = "exiftool" or LeftWords ( code ; 1 ) = "ffmpeg" ; "/usr/local/bin/" ); /* do shell script のみ: pbcopy にLANGを追加する */ code = If ( template = template_shell ; Substitute ( code ; "pbcopy" ; "LANG=ja_JP.UTF-8 pbcopy" ) ; "pbcopy" ) ; /* コマンドに sudo があるとき、パスワードを含める(セキュリティがばがばにつき注意) */ code = If ( PatternCount ( code ; "sudo " ); Substitute ( code ; "sudo " ; "echo '" & password & "' | sudo -S " ) ; code ); /* ダブルクォーテーションの変更、パスを囲む、複数行の処理、マイ変数の置き換え(カスタム関数) */ code = Substitute ( code ; "\"" ; "'" ) ; code = If ( PatternCount ( code ; " $POSIX" ) ; Substitute ( code ; [ "$POSIX1" ; "'$POSIX1'" ];[ "$POSIX2" ; "'$POSIX2'" ] ) ; code ) ; code = If ( PatternCount ( code ; ¶ ); Substitute ( code ; ¶ ; " ;" ) ; code ) ; code = If ( Right ( code ; 2 )=" ;" ; Left (code ; Length ( code ) -2 ) ; code ); code = paramを置換 ( code ) ;/* カスタム関数 */ /* 1行スクリプトのバックグラウンド処理(オマケ的。不要なら削る) */ code = If ( ValueCount (CodeTemp) = 1 and Right ( code ; 1 )≠ "&" ; code & " &" ; code ); /* 最終。commandを置換 */ code = Substitute ( template ; "$COMMAND" ; comPath & code ); /* category が command の場合のみ採用(それ以外は空) */ code = If (CodeRun::Category = "Command" ; code ) ]; code )
この計算式には、ここ DigitalBoo の挑戦の歴史と知見が込められていまして、同時に素人臭さにも満ちております。
ざっくり、何をしているのかということだけ書いていきます。Let関数使ってますので、順を追いますね。
テンプレートの選択
テンプレートを選択します。現状、二つのテンプレートを温存しているのでターミナルを使わないほうを選択しています。
template_shell = Template_DoShellScript; template = template_shell ;
テンプレートは「do shell script “$COMMAND”」というシンプルな一文なので、わざわざフィールドに収めたりテンプレートとして指定する意味はないのですが、かつてもうちょい複雑なテンプレートを使っていたときの名残でございます。
Macのパスワード
「sudo」のコマンドも実行させています。ターミナルでやるとMacのパスワードを訊かれます。これをなんと「password」というグローバルフィールドを利用して自動で送ってしまおうというセキュリティ感覚0の仕組みです。
password = password ;
ここでパスワードフィールドの内容を変数に保存して、のちほど「コマンドにsudoが含まれていれば」パスワードを自動で送り込みます。
パスワードをエコーしてパイプで sudo -S に繋げるということらしいのでそれでいきます。
code = If ( PatternCount ( code ; "sudo " ); Substitute ( code ; "sudo " ; "echo '" & password & "' | sudo -S " ) ; code );
良い子は真似してはいけませんが私は平気です。
… と思っていたらパスワードを使用せず sudo する書き方があるんですか。それをまだ知りませんので、今後の課題といたします。
次はいくつかの例外的措置です。
外部コマンドのパス
さて、ターミナルは賢いのでいきなりコマンドを書くことができますが、ターミナルをバイパスするとそうはいきません。自分でインストールしたツールを使用する場合はパスとセットで書く必要があります。以前、ExifTool が Automator で動作せずにドハマりしました。
/* do shell script のみ: 外部ツールにパスを加える */ comPath = If ( LeftWords ( code ; 1 ) = "exiftool" or LeftWords ( code ; 1 ) = "ffmpeg" ; "/usr/local/bin/" );
自分が使用する外部ツールだけを名指しで処理、すなわち、ExifToolとffmpeg の場合、コマンドの前に “/usr/local/bin/” を加えています。
個別具体的な対処の措置であり、汎用性のまったくない計算式です。他のツールを使っている方は自分用に書き加えます。
pbcopy に LANG を追加する
さらに限定的な措置で、めちゃ使いまくる pbcopy です。このコマンド、ターミナルで使うと賢いのですがターミナルじゃないところで使うとアホになります。 ターミナルでは「pbcopy」と書きますが、do shell script では「LANG=ja_JP.UTF-8 pbcopy」と書かねばまともな動作が出来ません。
code = If ( template = template_shell ; Substitute ( code ; "pbcopy" ; "LANG=ja_JP.UTF-8 pbcopy" ) ; "pbcopy" ) ;
このように、コマンド独自ルールを発見した場合には個別に計算式に追加していく必要があります。
ものを知らないので、今のところ挙動の違いを確認して解決できているのは pbcopy のみです。他にも同じようなのを発見すれば追加します。
仮置き変数の単純な置換
メインのCodeTempフィールドでは、パラメータ部分を変数文字で仮置きして、他のフィールドに実際の値を書きました。これを「検索・置換」関数を使って置き換えます。
単純な置き換えの前に、注意するポイントがあってその処理を先に済ませます。
コード内に ” ” とダブルクォーテーションがあれば シングルに置き換えます。
コード内に、何も括られていないパスがあれば ‘パス’ と、シングルクォーテーションで括ります。
コード内に改行があれば、; に置き換えます。コードの最後が ; で終わっていれば削除します。
/* ダブルクォーテーションの変更、パスを囲む、複数行の処理、マイ変数の置き換え(カスタム関数) */ code = Substitute ( code ; "\"" ; "'" ) ; code = If ( PatternCount ( code ; " $POSIX" ) ; Substitute ( code ; [ "$POSIX1" ; "'$POSIX1'" ];[ "$POSIX2" ; "'$POSIX2'" ] ) ; code ) ; code = If ( PatternCount ( code ; ¶ ); Substitute ( code ; ¶ ; " ;" ) ; code ) ; code = If ( Right ( code ; 2 )=" ;" ; Left (code ; Length ( code ) -2 ) ; code ); code = paramを置換 ( code ) ; /* カスタム関数 */
他は単なる置き換えです。コード内に $POSIX1 があれば param_posix1 で置き換えます。$NAME1 があれば param_name1 の内容で置き換えます。
単純なだらだらした置換なので、最後の部分はカスタム関数で処理しています。
/* カスタム関数はこんなの */ Substitute ( codeTemp ; [ "$POSIX2" ; CodeRun::param_POSIX2 ] ; [ "$POSIX1" ; CodeRun::param_POSIX1 ] ; [ "$POSIX" ; CodeRun::param_POSIX1 ] ; [ "$NAME1" ; CodeRun::param_NAME1 ] ; [ "$NAME2" ; CodeRun::param_NAME2 ] ; [ "$NAME" ; CodeRun::param_NAME1 ] ; [ "$TIMESTAMP2" ; CodeRun::param_TIMESTAMP2 ] ; [ "$TIMESTAMP1" ; CodeRun::param_TIMESTAMP1 ] ; [ "$TIME1" ; CodeRun::param_TIME1 ] ; [ "$TIME2" ; CodeRun::param_TIME2 ] ; [ "$EMAIL" ; CodeRun::param_EMAIL ] ; [ "$URL" ; CodeRun::param_URL ] ; [ "$COPYRIGHT" ; CodeRun::param_COPYRIGHT ] ; [ "$CREATOR" ; CodeRun::param_CREATOR ] )
最後にテンプレートの $COMMAND を置き換える
そんなこんなでコードが変換できたので、変換テンプレートの $COMMAND のところに置換でぶっ込みます。
code = Substitute ( template ; "$COMMAND" ; comPath & code );
以上で、コードを変換できましたが、Let関数の最後、ここでカテゴリーに応じて生かすか殺すかを決めます。カテゴリーが command であれば採用、そうでなければ空にしておきます。元々書かれたコードがAppleScriptやメモの場合は結果が空になります。
それを一番最初にやれよ。という声が今聞こえました。その通りですね。
/* category が command の場合のみ採用(それ以外は空) */ code = If (CodeRun::Category = "Command" ; code )
コマンドラインを do shell script に変換する CodeDoScript フィールドの計算式でした。
つづく
次は、実行するスクリプトについて です