pgrep.cmd / pkill.cmd ― 2008年09月29日 12時51分41秒
なんちゃってコマンド・番外編
ほんとはもうこの関連やらないつもりだっだんだけど、「FORコマンドで遊んでみる。」のコメント欄で、たけチンさんからリクエストをいただいたのでちょろっとやってみました。やっぱ同一名称のプロセス全殺しの需要があったか。
内容からして、基本は「FORコマンドで遊んでみる。」の「killでメモ帳を全て終了」で例示したコマンドをほぼそのまま使えるのでスクリプト作成なし、バッチファイルのみでやってます。
ただ、リクエストいただいたpgrep、pkillとも普段使ってないコマンドであまり詳しくないので、
最低限はプロセス名称でのgrepができればいいのですが、、、という最低限の実装しかしてません。ご容赦くださいな。 > たけチンさん
pgrep.cmd
まずはプロセスIDを列挙するpgrepから。基本はforコマンドにps+findstrの出力を渡してechoするだけなんだけども、
バッチ プログラムで FOR コマンドを使用するときは、%変数の代わりに、%%変数を使用してください。ってな注意書きがあるので、そのあたりに気をつけてこんな感じ。for /? より抜粋
@echo off for /f "tokens=1" %%p in ( '"ps -a| findstr -i %1"' ) do @echo %%pこの内容を「pgrep.cmd」とか「pgrep.bat」とかでパスが通ったところに保存すればOKです。まぁ、前提としてps.js、ps.cmd、kill.cmdがパスの通ったところに設置済みである必要がありますが。
いちおう以前配布したzipに含めたので、ps.jsとかを設置していない場合はこちらをダウンロードして、こちらのエントリを参考にして設置してみてくださいな。
技術的もは、findstr(というかクォートされたコマンド)にそのまま%1でバッチの引数渡せるか心配だったんだけど、やってみたらすんなり通ったのでこれで完成。
あ、findstrは無条件に -i オプション(ignore case)をつけちゃってます。だってwindowsだし。
pkill.cmd
もうね、さっきのバッチの「@echo」を「@kill」に変えるだけなんですよ。えぇ。
@echo off for /f "tokens=1" %%p in ( '"ps -a| findstr -i %1"' ) do @kill %%p設置の仕方はpgrep.cmdと同じです。当然zipに含めてあります。
試してみる
まず、メモ帳2つと、NOTEPAD++を起動した状態で、ps+findstrで確認。
C:\Documents and Settings\dara-j>ps -a | findstr -i notepad 9564 164 dara-j 4940 4940 0:00:00 notepad.exe 6456 164 dara-j 5048 5048 0:00:00 notepad.exe 8360 888 dara-j 828 17328 0:00:00 notepad++.exe C:\Documents and Settings\dara-j>んでpgrepしてみる。
C:\Documents and Settings\dara-j>pgrep notepad 9564 6456 8360 C:\Documents and Settings\dara-j>うん、3つ表示されますな。
じゃ、今度はメモ帳だけに限定。
C:\Documents and Settings\dara-j>pgrep "notepad.exe" 9564 6456 C:\Documents and Settings\dara-j>うん、ちゃんとnotepad++(PID:8360)が除外されてますな。あ、パターンをクォートするときはダブルクォートにしてください。シングルクォートだとキチンとパターン(バッチ中の「%1」)に渡せないので。
最後にpkillの確認。メモ帳だけ全殺し。
C:\Documents and Settings\dara-j>pkill "notepad.exe" C:\Documents and Settings\dara-j>pgrep "notepad.exe" C:\Documents and Settings\dara-j>pgrep notepad 8360 C:\Documents and Settings\dara-j>はい、notepad++だけは生き残ってます。当然画面上でもメモ帳のウィンドウがばっさり切られたと思います。ちなみに「pkill notepad」にするとnotepad++も殺されます。
関連記事
.svnディレクトリだけ列挙 ― 2008年09月07日 17時42分06秒
一週間ほど現実逃避をしていたら、もう9月すぎてるし。1ヶ月以上ブログ更新してないし。と思ったのだが、あんまりいいネタがないのでコネタ。
もうね、なんで気が付かないかな。
1ヶ月ほど前のエントリで「コマンドラインで.svnディレクトリを一括削除」なんてコマンドラインネタやったんだけど、このときは
- dirコマンドのオプションに /b(ファイル名のみ表示)、/s(指定ディレクトリ以降の再帰処理)に加えて隠しディレクトリを対象にするために/aオプションで属性未指定(=すべての属性を対象)として、
- 結果をfindstrの正規表現で「.svn」だけに絞り込む
dir /b/s/a | findstr /r \.svn$うん、タイプするのめんどくさいわ。
でね、もう一回dirコマンドのヘルプ見てみると、
/A 指定された属性のファイルを表示します。 属性 D ディレクトリ R 読み取り専用 H 隠しファイル A アーカイブ S システム ファイル - その属性以外
そんなわけで
さっきのパイプ付き処理を置き換えると、こんな感じ。
dir /b/s/a:dh *.svn/a:dh で「隠しディレクトリ」のみを対象とする、と。
だもんで、以前のエントリに掲載した.svnの再帰削除コマンド
for /f "tokens=*" %d in ('"dir /b/s/a | findstr /r \.svn$"') do rmdir /q/s "%d"なんて面倒なコマンドは、(比較的)シンプルに
for /f "tokens=*" %d in ('dir /b/s/a:dh *.svn') do rmdir /q/s "%d"なんてシンプルに置き換わります。無駄なファイル/ディレクトリの列挙もパイプ処理もないので当然こっちのほうがパフォーマンスいいし。測ってないけど。
あ、ファイル名の指定は通常のDOSワイルドカード指定になるので「.svn」じゃなくて「*.svn」になるとこだけは注意ね。
FORコマンドで遊んでみる。 ― 2008年08月04日 01時52分38秒
いや、実用性はないんだけども、前のエントリで覚えたばかりのFORコマンドと、ちょっと前に作ったなんちゃってコマンドを組み合わせて遊んでみたり。
chkconfig.jsの--detailを連続で
chkconfig.jsにオマケでつけてた--detailオプション、サービス名を指定しないと使えない仕様なんだけども、これをFORコマンドと組み合わせて使ってみると。
コマンドラインからcscript付きで指定するとちょっと冗長なので、ラッパーのバッチファイルを作っておくことにしよう。こんな感じで、「chkconfig.bat」とか「chkconfig.cmd」とか。
@echo off cscript //nologo "%~dP0\scripts\chkconfig.js" %*dara-jは特定のディレクトリにバッチ(というか.cmdファイル。単なる好みだけど)を設置することにしていて、そこにサブディレクトリ「scripts」を切って.jsはそこに置くようにしているので、chkconfig.jsのパス指定で「%~dP0\scripts\」としている。んで、バッチをおいたディレクトリにパスを通している。
で、chkncofig --listでサービスを列挙した後にfindstr Manualで手動起動設定になっているサービスのみに絞り込んで、それらに対してchkconfig --detailを適用してみる。
C:\Documents and Settings\dara-j>for /f "tokens=1" %d in ('"chkconfig --list | f indstr Manual"') do @chkconfig --detail %d サービス名 : AppMgmt 表示名 : Application Management スタートアップの種類 : 手動 状態 : 停止中 説明 : 割り当て、公開、削除などのソフトウェアのインストール サービスを供給します。 サービス名 : aspnet_state 表示名 : ASP.NET 状態サービス スタートアップの種類 : 手動 状態 : 停止中 説明 : ASP.NET の out-of-process セッション状態のサポートを提供します。このサービスが 中止されると out-of-process 要求は処理されません。このサービスが無効になると、こ のサービスに明示的に依存しているサービスはすべて開始できなくなります。 : (中略) : サービス名 : xmlprov 表示名 : Network Provisioning Service スタートアップの種類 : 手動 状態 : 停止中 説明 : 自動ネットワーク提供のための XML 構成ファイルをドメインごとに管理します。 C:\Documents and Settings\dara-j>結構重たい上なんの役にも立たないんだけども。
FORコマンド中で「tokens=1」と指定しているのは、chkconfig --listの出力結果からサービス名のみを抽出するため。FORコマンドの既定の区切り文字(空白とタブ、らしい)で各行がトークン単位に分割されるのだが、chkconfigの出力の場合は、先頭がサービス名になるのでそのように指定している。
killでメモ帳を全て終了
今度は多少は使い道あるかなぁ。こちらの「ps.jsとps.cmd / kill.cmd」で作ったpsとkillを使って、特定のプロセスをまとめて終了させると。
まず適当にnotepadをいくつか起動する。
C:\Documents and Settings\dara-j>ps | findstr notepad 1456 5788 dara-j 4708 4708 0:00:00 notepad.exe 5316 5788 dara-j 4852 4852 0:00:00 notepad.exe 4228 5788 dara-j 4716 4716 0:00:00 notepad.exe 4992 5788 dara-j 4720 4720 0:00:00 notepad.exe 5544 5788 dara-j 4696 4696 0:00:00 notepad.exe C:\Documents and Settings\dara-j>こんな感じで5個のメモ帳が動いてるとして、
C:\Documents and Settings\dara-j>for /f "tokens=1" %d in ('"ps | findstr notepad "') do @kill %d C:\Documents and Settings\dara-j>ってな感じでnotepad.exe全殺し。やっぱ役に立たないかな。
コマンドラインで.svnディレクトリを一括削除 ― 2008年08月04日 01時05分23秒
DIR コマンドにこんな使い方が
なにを探しているときに見つけたかすでに忘れたのだが、しばらく前にこんなTIPSを見つけた。
タイトルにあるとおり、
dir /b/s somedirってやると、UNIX/Linuxのfindコマンドよろしく、指定ディレクトリ以下のファイルをフルパスで列挙してくれる。
例えば、dara-jの手持ちの環境ではZend Framework 1.0.0を D:\PHP\libs\Zend 以下に設置しているのだが、こんな感じで列挙できる。
C:\Documents and Settings\dara-j>dir /b/s D:\PHP\libs\Zend\*.php D:\PHP\libs\Zend\Acl.php D:\PHP\libs\Zend\Auth.php D:\PHP\libs\Zend\Cache.php D:\PHP\libs\Zend\Config.php D:\PHP\libs\Zend\Date.php D:\PHP\libs\Zend\Db.php D:\PHP\libs\Zend\Debug.php : (中略) : D:\PHP\libs\Zend\XmlRpc\Value\DateTime.php D:\PHP\libs\Zend\XmlRpc\Value\Double.php D:\PHP\libs\Zend\XmlRpc\Value\Exception.php D:\PHP\libs\Zend\XmlRpc\Value\Integer.php D:\PHP\libs\Zend\XmlRpc\Value\Scalar.php D:\PHP\libs\Zend\XmlRpc\Value\String.php D:\PHP\libs\Zend\XmlRpc\Value\Struct.php C:\Documents and Settings\dara-j>はぁ、こんなことできたんだぁ。
ヘルプで調べてみると
dir /?でそれぞれのオプションがどんな意味があるのか見てみたところ、
/B ファイル名のみを表示します (見出しや要約が付きません)。dir /? より抜粋
/S 指定されたディレクトリおよびそのサブディレクトリのすべての ファイルを表示します。dir /? より抜粋
なるほど、/bで属性などをつけずファイル名(というより、絶対パスみたいなのだが)のみ、/sで再帰処理なことはよくわかった。しかし、何度かこの説明文は見たことあるんだけど、さっぱり気がつかなかった。
その列挙を利用して...
これだけでも割と目から鱗チックだったんだけど、リンク先にはさらにこんなコマンドが載っていた。
リダイレクトしない場合はforコマンドが使えます。うーん、よくわからんが、どうやらIISがらみの特定のディレクトリかファイルを再帰処理で一括削除しているみたい。
C:\Inetpub\wwwroot> for /f %d in ('dir /b/s _vti_cnf') do rmdir /q/s %d
つか、FORコマンド??
for /?で見てみると(長いヘルプなのでテキストファイルに書き込むと吉)、どうやらこれが該当するのかな。
FOR /F ["オプション"] %変数 IN ('コマンド') DO コマンド [コマンド パラメータ]説明を見てもなんだか冗長でイマイチ把握しづらいんだけど、()内の一重引用符で囲まれた「dir /b/s _vti_cnf」の結果を変数 %d に逐次当てはめながら、do 以降で指定されているコマンド「rmdir /q/s %d」に渡しているんだろうと。for /? より抜粋
なるほどねぇ、dir /b/s でファイルのフルパスがあがってくるので、これをforコマンドにまわせばループ処理できるんだ。
.svnディレクトリを再帰的に削除してみたり
んで、やっとこ本題。
Subversionの作業コピーって、各ディレクトリにメタデータディレクトリ「.svn」が隠しディレクトリとして追加されてるのよね。
ローカルで作業してるときはいいんだけど、これをどっかに配布したりするのに、このメタデータが邪魔なので削除してみようかと。いや、当然エクスポートすればいいのは知ってるんだけどね。
いきなり結論。
for /f "tokens=*" %d in ('"dir /b/s/a | findstr /r \.svn$"') do rmdir /q/s "%d"ここにいたるまで若干の紆余曲折はあったんだけど、要点は以下。
- dirコマンドには /aオプションもつける → .svnディレクトリが隠し属性だから。
- .svnディレクトリだけ処理したいので、findstrで「\.svn$」という正規表現で限定してる。もっとうまいやり方あるかな。
- dir → findstrとパイプでうまくつなげるには二重引用符でくくる。上のコマンドをよーく見てみて。
- パスに空白が入る場合に対応して、/fの後にオプション「tokens=*」で1行すべてを1トークンとして認識させる
- 同様に空白対策で、rmdirに渡すときに、%d自体を二重引用符でくくる
うん、こんな覚えづらいコマンドでちくちくするより「svn export --force work_dir target」したほうがよっぽど速いんだけども。
追記(08.9.7)
svn exportはおいておいて、dirコマンドのオプションでもう少し簡単になりました。
ps.jsとps.cmd / kill.cmd ― 2008年06月17日 00時54分14秒
なんちゃってコマンド 第四弾
我ながらしつこいなと思いつつ「なんちゃってコマンド」スクリプト。今度はps作ってみました。
ま、WMIでWin32_Process列挙できればそんなに難しくないので、似たようなことやってる人はいるだろなぁ。
例によってソース
ちょっと長いけど例によってのっけときます。NYSLです。
var fso = new ActiveXObject("Scripting.FileSystemObject"); var shell = new ActiveXObject("WScript.Shell"); // コマンドライン引数の取得 var args = new function() { var args = WSH.Arguments, result = []; for(var col = new Enumerator( args ); ! col.atEnd(); col.moveNext()) { result[ result.length ] = String( col.item() ); } var named = {}; for(var col = new Enumerator( args.Named ); ! col.atEnd(); col.moveNext()) { named[ String( col.item() ) ] = String( args.Named.Item( col.item() ) ); } var unnamed = []; for(var col = new Enumerator( args.Unnamed ); ! col.atEnd(); col.moveNext()) { unnamed[ unnamed.length ] = String( col.item() ); } result.named = named; result.unnamed = unnamed; result.toArray = function() { var result = []; for(var i = 0, l = this.length; i < l; i++) { result[ i ] = /((^".*"$)|(^'.*'$))/.test( this[i] ) ? this[i] : [ '"', this[i], '"' ].join(""); } return result; }; result.toString = function() { return this.toArray().join(" "); }; return result; }(); // cscriptで強制起動 if( /wscript\.exe$/i.test( WSH.FullName ) ) { shell.Run( [ "cscript", /((^".*"$)|(^'.*'$))/.test( WSH.ScriptFullName ) ? WSH.ScriptFullName : [ '"', WSH.ScriptFullName, '"' ].join(""), args ].join(" ") ); WSH.Quit(); } // ユーティリティ関数定義 var echo = function(s) { print( [ s, "\n" ].join("") ); } var print = function(s) { WSH.StdOut.Write( s || "" ); } var input = function() { if( arguments[0] ) print( arguments[0] ); print( ">" ); return WSH.StdIn.ReadLine(); } Error.prototype.toString = function() { return this.description || this.message || this.number || this; }; var $break = {}; var $continue = {}; Enumerator.prototype.each = function(iterator) { try { var i = 0; for(this.moveFirst(); ! this.atEnd(); this.moveNext()) { try { iterator( this.item(), i++ ); } catch(e) { if( e != $continue ) throw e; } } } catch(e) { if( e != $break ) throw e; } }; String.prototype.repeat = function(count) { var buf = []; for(var i = 0; i < count; i++) buf[buf.length] = this; return buf.join(""); }; String.prototype.align = function(align, size) { if( ! /^((left)|(right)|(center))$/i.test( align ) ) align = "left"; if( isNaN(size) || size < 1 ) size = this.length; switch( align ) { case "left": return [ this, " ".repeat(size) ].join("").substr(0, size); case "right": return [ " ".repeat(size), this ].join("").slice(-1 * size); default: var pad = " ".repeat( size ); var s = [ pad, this, pad ].join(""); return s.substr( parseInt(s.length / 2) - parseInt(size / 2), size ); } }; Number.prototype.toTime = function() { var sec = this % 60; var min = Math.floor( this / 60 ); var hour = Math.floor( min / 60 ); min = hour ? min % 60 : min; return [ hour, ( "00" + min ).slice(-2), ( "00" + sec ).slice(-2) ].join(":"); }; var ProcMgr = function() { this.wmi = new ActiveXObject("WbemScripting.SWbemLocator").ConnectServer(); var wshNet = new ActiveXObject("WScript.Network"); this.currentUser = [ wshNet.UserDomain, wshNet.UserName ].join("\\"); }; ProcMgr.prototype = { list : function(id) { var query = "SELECT * FROM Win32_Process"; query += id != null ? [ " WHERE ProcessId = ", id ].join("") : ""; return new Enumerator( this.wmi.ExecQuery(query) ); }, kill : function(id) { this.list(id).each( function(proc) { proc.Terminate(); throw $break; } ); }, exec : function(params) { if( params[0] && params[0].toLowerCase() == "--kill" && params[1] ) { // --kill this.kill( params[1] ); } else if( params[0] && params[0].toLowerCase() == "--list" ) { // --list // -a オプション。全ユーザのプロセスを列挙 var allUser = ( params[1] != null && /^-.*A/i.test( params[1] ) ); // -d オプション。コマンドラインの情報を付加 var detail = ( params[1] != null && /^-.*d/i.test( params[1] ) ); var inited = false; var _self = this; this.list().each( function(proc) { if( ! inited ) { inited = true; echo( [ "PID".align( "right", 5 ), "PPID".align( "right", 5 ), "OWNER".align( "left", 16 ), "WK-SIZE".align( "right", 8 ), "PEAK".align( "right", 8 ), "TIME".align( "right", 10 ), "CMD".align( "left", 16 ) ].join(" ") ); } var cmd = proc.CommandLine == null ? "(null)" : String( proc.CommandLine ); var time = parseInt( ( Number(proc.KernelModeTime) + Number(proc.UserModeTime) ) / 10000 / 1000 ); var info = proc.ExecMethod_( proc.Methods_.Item("GetOwner").Name, null ); // プロセスオーナーのチェック if( ! allUser && [ info.Domain, info.User ].join("\\").toLowerCase() != _self.currentUser.toLowerCase() ) throw $continue; echo( [ String(proc.ProcessId).align( "right", 5 ), String(proc.ParentProcessId).align( "right", 5 ), String(info.User || "(null)" ).align( "left", 16 ), String(Number(proc.WorkingSetSize) / 1024).align( "right", 8 ), String(Number(proc.PeakWorkingSetSize) / 1024).align( "right", 8 ), String( time.toTime() ).align( "right", 10 ), [ String(proc.Name), detail ? [ "(", cmd, ")" ].join("") : "" ].join(" ") ].join(" ") ); } ); } else { // no parameter -> --list this.exec( [ "--list" ] ); } } }; new ProcMgr().exec( args );今回のダウンロードはzip形式にしてます。こちらからどうぞ。
使い方
今回は不精して、1つのスクリプトで2つのコマンドを兼用しています。おかげでjsファイルとしての呼び出しはちと不自然な感じなんですが。
プロセスの列挙 - psコマンド風味
何も引数をつけずに起動すると psコマンドっぽく(?)稼動中のプロセスを列挙します。ただし、標準入力での入力待ちを行わないので、明示的にcscriptで起動したほうがよいでしょう。
C:\ps_command\scripts>cscript ps.js Microsoft (R) Windows Script Host Version 5.6 Copyright (C) Microsoft Corporation 1996-2001. All rights reserved. PID PPID OWNER WK-SIZE PEAK TIME CMD 472 1532 dara-j 2072 4912 0:01:01 tp4serv.exe 2172 2112 dara-j 29992 95644 0:42:34 explorer.exe 2272 2172 dara-j 4384 6808 0:00:30 TSVNCache.exe : (中略) : 1640 2172 dara-j 2840 2884 0:00:00 cmd.exe 4920 1640 dara-j 6612 6612 0:00:00 cscript.exe C:\ps_command\scripts>列の意味は、左から
- PID - プロセスID
- PPID - 親プロセスID
- OWNER - プロセスのオーナー
- WK-SIZE - ワーキングセット サイズ
- PEAK - ピークメモリサイズ
- TIME - CPU時間(カーネル+ユーザ)
- CMD - コマンドイメージ名
また、第一引数に「--list」をつけた場合も上と同じ動作になります。
C:\ps_command\scripts>cscript ps.js --list Microsoft (R) Windows Script Host Version 5.6 Copyright (C) Microsoft Corporation 1996-2001. All rights reserved. PID PPID OWNER WK-SIZE PEAK TIME CMD 472 1532 dara-j 2072 4912 0:01:01 tp4serv.exe 2172 2112 dara-j 29928 95644 0:42:39 explorer.exe 2272 2172 dara-j 4384 6808 0:00:30 TSVNCache.exe : (中略) : 1640 2172 dara-j 2840 2884 0:00:00 cmd.exe 5864 2172 dara-j 1888 6716 0:00:01 taskmgr.exe 5212 1640 dara-j 6604 6604 0:00:00 cscript.exe C:\ps_command\scripts>
--listで起動した場合はさらに第二引数にオプションをつけることができます。
「-a」オプションをつけると、他のオーナーが所有するプロセスも列挙します。といってもだいたい「SYSTEM」や「NETWORK SERVICE」くらいでしょうが。
C:\ps_command\scripts>cscript ps.js --list -a Microsoft (R) Windows Script Host Version 5.6 Copyright (C) Microsoft Corporation 1996-2001. All rights reserved. PID PPID OWNER WK-SIZE PEAK TIME CMD 0 0 (null) 16 0 73:50:31 System Idle Process 4 0 SYSTEM 36 2040 0:05:51 System 836 4 SYSTEM 44 480 0:00:00 smss.exe : (中略) : 1932 2172 dara-j 2848 2864 0:00:00 cmd.exe 4696 1932 dara-j 6624 6624 0:00:00 cscript.exe 3356 1168 NETWORK SERVICE 5728 5728 0:00:00 wmiprvse.exe C:\ps_command\scripts>
これは個人的な趣味でつけたのですが、「-d」オプションをつけると、起動時のコマンドライン(引数まで込み)を出力します。
C:\ps_command\scripts>cscript ps.js --list -d Microsoft (R) Windows Script Host Version 5.6 Copyright (C) Microsoft Corporation 1996-2001. All rights reserved. PID PPID OWNER WK-SIZE PEAK TIME CMD 472 1532 dara-j 2072 4912 0:01:02 tp4serv.exe ("C:\Progr am Files\Lenovo\TrackPoint\tp4serv.exe") 2172 2112 dara-j 30244 95644 0:43:04 explorer.exe (C:\WINDO WS\Explorer.EXE) 2272 2172 dara-j 4408 6808 0:00:30 TSVNCache.exe ("C:\Pro gram Files\TortoiseSVN\bin\TSVNCache.exe") : (中略) : 5864 2172 dara-j 2632 6716 0:00:10 taskmgr.exe (C:\WINDOW S\system32\taskmgr.exe) 1932 2172 dara-j 5516 5592 0:00:00 cmd.exe ("cmd.exe" /K cd C:\ps_command) 2260 1932 dara-j 6624 6624 0:00:00 cscript.exe (cscript p s.js --list -d) C:\ps_command\scripts>複数インスタンス起動できるエディタなんかの、あるインスタンスを特定する場合なんかに便利かなとか思ってつけたのですが、正直表示が見づらいです。まぁオマケ機能くらいの感じで。
実行例は示しませんが、「-a」と「-d」は「-ad」といった具合で同時に指定できます。
プロセスの強制終了 - killコマンド風味
第一引数に「--kill」をつけるとkillモードで起動します。この呼び出し方法は第二引数にプロセスIDを必ず指定する必要があります。
以下はメモ帳(notepad.exe)を起動し、プロセスIDを確認後にkillモードで終了させる例です。
C:\ps_command\scripts>notepad C:\ps_command\scripts>cscript ps.js | findstr notepad 5728 1932 dara-j 4888 4888 0:00:00 notepad.exe C:\ps_command\scripts>cscript ps.js --kill 5728 Microsoft (R) Windows Script Host Version 5.6 Copyright (C) Microsoft Corporation 1996-2001. All rights reserved. C:\ps_command\scripts>cscript ps.js | findstr notepad C:\ps_command\scripts>
バッチファイル
見てきたように2種類の動作を1つのスクリプトに集約したため、ちょっと引数が気持ち悪いのですが、バッチファイルを添付してあるので勘弁してください(ダウンロードファイルをzipにしたのはこのため)。
ダウンロードファイルを解凍すると、以下のような構造になっています。
- ps_command/
- scripts/
- ps.js - スクリプト本体
- kill.cmd - killモード起動用のバッチファイル
- ps.cmd - psモード起動用のバッチファイル
- scripts/
バッチファイルはスクリプトパスを「"%~dP0\scripts\ps.js"」としているため、「ps_command」フォルダごとリロケータブルになっています。「%~dp0」がなんなのかはこちらのサイトなんかが参考になるのでは。
ps.cmdは見れば即わかるくらいシンプルですが、kill.cmdは引数なしの時にusageを表示する分岐処理を入れてます。まぁぜんぜん難しいことしてるわけではないのですが。
その他
なんというか、できそうだからやってみました、以上のことがないようなネタですが。本当はvmstatとかfreeとかもやろうかと思ったけど、まんまlinuxと同じ情報があるわけでなし、なにを出力するか考えるのも面倒になってきたのでなんちゃってシリーズはこれでおしまいかな。
ま、そうはいっても今回はCPU時間とかオーナー情報の取得でちとてこずったので、そこらへんを別記事にまとめる予定。
最近のコメント