Hatena::ブログ(Diary)

分室の分室 このページをアンテナに追加

2012-01-22 Sun

【190】 Windows 用の『拡張 cd コマンド(xcd)』を制作中…

【訂正あり(xcd.pl ソース:打ち消し線)】
【さらに追記:2012.01.22 Sun 11:33】
アチコチに不具合があるみたい…初版(v0.00)なので、大目に見てください… (^^;

【さらにさらに追記:2012.01.24 Tue 03:41】
しつこく検証した結果、さほどの不具合はなかった…ま、未完成なのは確かだけど。。。

 Windows でのプログラミング環境をちょっとだけ改善したい。個人でプログラ
ミングするだけなら、多機能な IDE は要らない(複雑すぎて使い方が分かんない
し、プロジェクト管理やバージョン管理は不要だと思うし…)。

 以前、ezcd.bat  というものを作ってみたが、それをもうチョビっと膨らませ
たものを作ろうと思っている。

 で、骨子だけのプログラムを、とりあえず作ってみた。

------------------------------------------------------------------------
名前:xcd.bat                       (eXtended ChDir :現行プロセス実行)
      xcd.env                       (Perl スクリプト:環境設定ファイル)
      xcd.pl                        (Perl スクリプト:子プロセス実行)

動作条件:Windows XP 以降で動作     (findstr, pushd, popd コマンド必要)
          Perl も必要               (v5.6 以降)

書式1:xcd ファイルスペック         (拡張 chdir コマンドとして実行)
書式2:xcd ファイルスペック -bin    (bin ファイル検証モード)
書式3:xcd ファイルスペック -lib    (lib ファイル検証モード)
書式4:xcd                          (実効ステータス情報の表示)
書式5:xcd -install                 (検証モードを終了、インストール実行)
書式6:xcd -help                    (簡易 help を標準エラー出力)
書式7:xcd --help                   (詳細 help を標準出力)

引数:『-』から始まる文字列は『オプション』と断定する。 よって、ファイル
       スペックは『-』から始まってはならない。

備考:xcd.env, xcd.pl は、xcd.bat と同じディレクトリに置く。そのディレク
      トリは『環境変数 PATH』に記述されている場所とする。
------------------------------------------------------------------------

 上記は予定で、とりあえず『書式1』だけ実現した。 現時点でのソースはこん
な感じ。

xcd.bat

@echo off

goto SKIP
------------------------------------------------------------------------
名前:xcd.bat
版  :v0.00
書式:xcd ファイルスペック
文例:xcd *ムリ.jpg

動作条件:findstr, pushd, popd コマンドが使える Windows。
          あと、Perl も必要。
------------------------------------------------------------------------
:SKIP

dir %1 /s > ezcd.tmp
findstr /r /c:" のディレクトリ$" ezcd.tmp >ezcd.match
del ezcd.tmp

rem /* ここで Perl を起動。ezcd.match の読込、そして削除          */
rem /* (子プロセスで出来ることだけやる)                           */
rem /* call xcd.pl  …だけで実行可能                              */
rem /*              (今どきの Windows ならこっちの方が高速?)      */
rem /* call perl -S xcd.pl                                        */
rem /*              …は Windows のインデクスを使わないので遅い?  */
call xcd.pl

rem /* xcd.pl が生成した xcd-tmp.bat でカレントディレクトリを変更 */
for %%f in (%path%) do if exist %%f\xcd-tmp.bat set 存在=%%f\xcd-tmp.bat
if not "%存在%"=="" pushd .\
if not "%存在%"=="" call %存在%

rem /* xcd-tmp.bat を削除(option -del) */
call xcd.pl -del

echo.
if not "%存在%"=="" dir
if not "%存在%"=="" echo.
set 存在=

xcd.pl

#!/usr/local/bin/perl

use strict;
use warnings;
require 5.006;

# xcd.pl (Windows 専用) by foussin
# v0.00:2012.01.22 Sun 05:45  初版

### 初期設定
#   (xcd.bat と同じディレクトリに置く = パスが通っている = 実行可能)
my $myname  = "xcd.pl";     # 変更不可
my $envname = "xcd.env";    # 変更不可
my $ezcdtmp = "ezcd.match";     # xcd.bat にも記述されている
my $tmp_bat = "xcd-tmp.bat";    # xcd.bat にも記述されている
my $sep     = ';';              # ここが Windows 専用

### 実行中の自分(xcd.pl)がいる場所を PATH から探し、@INC の先頭に登録。
# (これで、xcd.bat と同じ場所にある設定ファイルを、require で読み込める)
# $mypath は『一時ファイル』の置き場所としても使う。xcd.bat は、カレント
# ディレクトリを変更する。一時ファイルは既知の絶対パスに置いた方が賢明。
my $mypath  =  mypath($myname, $sep);

### 環境設定ファイルの読込
require $envname;

### 一時ファイルの除去
$ARGV[0] or $ARGV[0] = "";
if ($ARGV[0] eq "-del") {
    xcd_env::del();
} else {

### 以降 本体 ↓↓↓

### 一時ファイル $ezcdtmp(ezcd.match)の読込、そして削除
#   (ezcd.match はカレントディレクトリに出力済)
open(IN, $ezcdtmp) or die;
my @dir_list;
while (<IN>) {
    chomp;
    $_ =~ s/^ (.*) のディレクトリ$/$1/;
    push(@dir_list, $_);
}
close IN;
unlink $ezcdtmp;

# 今後、一時ファイルは $mypath に作成する

### ディレクトリの選択メニュー
my $num   = @dir_list;
my $input = 0;
unless ($num) {
    die "file not found!\n\n";
}
if ($num > 16) {
    print STDERR "\n$num 個のディレクトリがマッチしました。\n";
    print STDERR "検索条件を絞って再実行してください。\n";
    die;
} elsif ($num > 1) {
    print STDERR "\n$num 個のディレクトリがマッチしました。\n";
    print STDERR "cd するディレクトリを選択してください。\n\n";
    for (my $i=0; $i<@dir_list; ++$i) {
        printf "%02d: $dir_list[$i]\n", $i;
    }
    print "選択(0-", $num - 1, ")> ";
    $input  = <STDIN>;
    $input += 0;
}
my $target_dir = $dir_list[$input];

### $mypath に $tmp_bat(xcd-tmp.bat)を作る
#   (xcd-tmp.bat は親プロセスで cd を実行する)
$tmp_bat = $mypath . "/" . $tmp_bat;
open(BAT, ">$tmp_bat") or die;
print BAT "cd $target_dir\n";
close BAT;

### 環境設定ファイル(xcd.env) に一時ファイル(xcd-tmp.bat)のリストを追記
#   (あとで削除するための情報)
open(IN,  "<$mypath/$envname")      or die;
open(OUT, ">$mypath/$envname.tmp")  or die;
while (<IN>) {
    chomp;
    if ($_ =~ /my \$del = /) {
        print OUT "    my \$del = '$tmp_bat';\n";
    } elsif ($_ =~ /^# last executed:/) {
        my $date = localtime;
        print OUT "# last executed: $date (JST)\n";
    } else {
        print OUT "$_\n";
    }
}
close   IN;
close   OUT;
unlink  "$mypath/$envname";
rename  "$mypath/$envname.tmp", "$mypath/$envname";
unlink  "$mypath/$envname.tmp";


} # end of 本体

# ここまでの処理は『子プロセス』実行時のみ有効

# ----------------------------------------------------------------------
# sub routine
# ----------------------------------------------------------------------

# 実行中の自分自身がいる場所を PATH から探し、@INC の先頭に登録
# 書式:$mypath = mypath($myname, $sep);
# 引数:$myname ... 自分のファイル名
# 引数:$sep ...... 区切り文字 (Windows なら ";") (Linux なら ":")
# 戻値:$mypath ... @INC パスだけでなく、一時ファイル、環境設定ファイル
#                   の保存先としても利用できる。
sub mypath {
    my ($name, $sp) = @_;
    my $env   =  $ENV{"PATH"};
  # / 区切りに変更(Windows を想定 … sjis のパス名は化ける)
    ($sp eq ";") and $env =~ tr|\\|/|;
    my @path  =  split(/$sp/, $env);
    my $path  =  "";
    foreach my $p (@path) {
        $p    or next;            # ;; と記述されている場合があるので
        $p    =~ s|(.*)/$|$1|;    # 末尾の / はトル
        $path =  $p;
        (-e $path . "/$name") and last;
        $path = "";
    }
    unshift @INC, $path;          # $path を @INC に追加
    return $path;
}

__END__
これ以降にヘルプを記述する予定…

------------------------------------------------------------------------
名前:xcd.bat                       (eXtended ChDir :現行プロセス実行)
      xcd.env                       (Perl スクリプト:環境設定ファイル)
      xcd.pl                        (Perl スクリプト:子プロセス実行)

動作条件:Windows XP 以降で動作     (findstr, pushd, popd コマンド必要)
          Perl も必要               (v5.6 以降)

書式1:xcd ファイルスペック         (拡張 chdir コマンドとして実行)
書式2:xcd ファイルスペック -bin    (bin ファイル検証モード)
書式3:xcd ファイルスペック -lib    (lib ファイル検証モード)
書式4:xcd                          (実効ステータス情報の表示)
書式5:xcd -install                 (検証モードを終了、インストール実行)
書式6:xcd -help                    (簡易 help を標準エラー出力)
書式7:xcd --help                   (詳細 help を標準出力)

引数:『-』から始まる文字列は『オプション』と断定する。 よって、ファイル
       スペックは『-』から始まってはならない。

備考:xcd.env, xcd.pl は、xcd.bat と同じディレクトリに置く。そのディレク
      トリは『環境変数 PATH』に記述されている場所とする。

------------------------------------------------------------------------
書式1:xcd ファイルスペック         (拡張 chdir コマンド)

目的:ファイルスペックにマッチするファイルが存在するディレクトリを探し、
      その場所をカレントディレクトリにする。その直前、現在のカレントディ
      レクトリを pushd で保存するので、popd を実行すれば元のディレクトリ
      に戻ることができる。内部では…

      dir /s ファイルスペック

      を実行するので、基本的には『サブディレクトリ』を探索する。親ディレ
      クトリから探索を始めたい場合は…

      ..\ファイルスペック

      と指定すれば良いが、探索の範囲を広げすぎるのは推奨できない。

      複数のディレクトリがマッチした場合は、カレントにしたいディレクトリ
      を選択するメニューが表示される。但し、メニュー表示は最大16行(0-15)
      までとする。17個以上のディレクトリがマッチした場合…

          nn 個のディレクトリがマッチしました。
          検索条件を絞って再実行してください。

      と表示して実行中止する。
------------------------------------------------------------------------

 書式1 を実現してみる。→ 2012.01.22 Sun 05:09 完了 (xcd v0.00)

xcd.env

# xcd.pl (xcd.bat) が利用する環境設定ファイル
# (ここでの処理は『子プロセス』実行時のみ有効)

#---------------------------------------------------------------------
#use strict;        # これを記述すると、変数宣言しただけで使ってない…
#use warnings;      # …と怒られるので、記述しない。
#---------------------------------------------------------------------

require 5.006;
package xcd_env;
my $myname = "xcd.env";

###############################################
# ユーザー設定ブロック
###############################################

# これから仕様を考える…


###############################################
# 以降は xcd.pl が自動的に追記する(変更不可)
# (前回に実行した記録が残る)
###############################################
# last executed:

# 一時ファイルを最後に削除する
sub del {
    my $del = '';
    (-f $del) and unlink $del;
}

1;

__END__

実行例

 こんな風に使う。↓

c:\usr\edit>xcd xcd.bat ドライブ C のボリューム ラベルは c-boot です ボリューム シリアル番号は USO-800 です c:\usr\edit\test-bin\xcd_bat のディレクトリ 12/01/21 (土) 10:27 <DIR> . 12/01/21 (土) 10:27 <DIR> .. 12/01/21 (土) 10:27 <DIR> ezcd_bat 12/01/21 (土) 04:30 <DIR> old 12/01/19 (木) 16:05 <DIR> 検証済 12/01/22 (日) 06:40 1,222 xcd.bat 12/01/22 (日) 05:34 894 xcd.env 12/01/22 (日) 05:51 7,286 xcd.pl 12/01/21 (土) 04:12 30 cd.txt 12/01/22 (日) 04:37 5,867 xcd_making.txt 12/01/22 (日) 05:40 8,866 xcd_memo.txt 6 個のファイル 24,165 バイト 5 個のディレクトリ 67,257,372,672 バイトの空き領域 c:\usr\edit\test-bin\xcd_bat>
 拡張 cd コマンドといっても、引数はフォルダ名(ディレクトリ名)ではなく、 『ファイル名(ワイルドカードが使える)』を指定する。そして…
c:\usr\edit\test-bin\xcd_bat>popd c:\usr\edit>
 popd を実行すると、直前のディレクトリに戻れる。内部で pushd を実行して いるので。ワイルドカードでファイル名を指定すると、こうなる。↓
c:\usr\edit>xcd *.jpg ←テキトーに実行 122 個のディレクトリがマッチしました。 検索条件を絞って再実行してください。 Died at C:\usr\bat\xcd.pl line 58. c:\usr\edit>xcd doc\*.jpg ←検索条件を絞って再実行 13 個のディレクトリがマッチしました。 cd するディレクトリを選択してください。 00: c:\usr\edit\doc\references\fsb_draft\img_etc 01: c:\usr\edit\doc\references\fsb_draft\img_fedora 02: c:\usr\edit\doc\下書き\old\image 03: c:\usr\edit\doc\下書き\はてなダイアリー用 04: c:\usr\edit\doc\下書き\はてなダイアリー用\2012白川静_cal\450px 05: c:\usr\edit\doc\下書き\はてなダイアリー用\2012白川静_cal\480px 06: c:\usr\edit\doc\下書き\はてなダイアリー用\2012白川静_cal\old 07: c:\usr\edit\doc\下書き\はてなダイアリー用\2012白川静_cal\pending 08: c:\usr\edit\doc\下書き\はてなダイアリー用\hatena_img 09: c:\usr\edit\doc\下書き\デジカメ 10: c:\usr\edit\doc\下書き\デジカメ\100OLYMP 11: c:\usr\edit\doc\下書き\陸前高田\image 12: c:\usr\edit\doc\下書き\陸前高田\image\100OLYMP 選択(0-12)> 5 ドライブ C のボリューム ラベルは c-boot です ボリューム シリアル番号は USO-800 です c:\usr\edit\doc\下書き\はてなダイアリー用\2012白川静_cal\480px のディレ… 12/01/10 (火) 23:27 <DIR> . 12/01/10 (火) 23:27 <DIR> .. 12/01/10 (火) 22:48 33,993 0-2012-01-11-ホントに.JPG 12/01/10 (火) 22:21 38,253 1-2012-01-11-ムリ.JPG 12/01/10 (火) 23:25 28,702 2-2012-01-11-だめだ.jpg 12/01/10 (火) 22:32 29,727 3-2012-01-11-やっぱり.JPG 4 個のファイル 130,675 バイト 2 個のディレクトリ 67,257,372,672 バイトの空き領域 c:\usr\edit\doc\下書き\はてなダイアリー用\2012白川静_cal\480px>
 とりあえず、こんな感じ。今のままだと、さほど便利さは感じないけど、 start 2-2012-01-11-だめだ.jpg …とかやれば、 .jpg に関連付けされたアプリケーションで画像を開くことが出 来る。 はっきり言って、実行速度は遅いですが、何度も実行すれば Windows の キャッシュが働くので、まあいいかな、と思っている。  今後は『検証モード』という機能を追加して、bin形式ファイル、lib形式ファ イルの動作検証が出来るように、環境変数『PATH』『PERL5LIB』にカレントディ レクトリを一時追記できるようにするつもりでいる。  本日は、ここまで。

foussinfoussin 2012/01/22 12:08 自己レス。
wait を入れる必要があるかも。
Windows の場合、どうするか…
インターバル・タイマーを使ってみる?
Time::HiRes だっけ。。。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

トラックバック - http://d.hatena.ne.jp/foussin/20120122/1327191083