2022年5月
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        
無料ブログはココログ

« 2007年2月 | トップページ | 2007年4月 »

2007年3月31日 (土)

unix tee擬似バッチファイル(その2)

標準入力を読んで、標準出力と標準エラーに出力します。

@if(0)==(0) ECHO OFF
CScript.exe //NoLogo //E:JScript "%~f0"
GOTO :EOF
@end
while(!WScript.StdIn.atEndOfStream){
  var c=WScript.StdIn.Read(1);
  WScript.StdOut.Write(c);
  WScript.StdErr.Write(c);
}

2007年3月27日 (火)

イメージファイルのURLを安全に表示するには?

イメージファイルのURLを直接、入力して表示することは、危険です。
それが信頼済みサイトのURLの場合は、特に、危険です。
もしも、HTMLがイメージファイルに埋め込まれていると、
クロスサイトスクリプティングの危険があります。

イメージファイルのURLを<img>タグに指定すれば、安全です。
そのために、いちいち、<img>タグだけのHTMLファイルを作るのも、なんです。

「ファイル名を指定して実行」に、
about:<img src='http://...'>

コマンドプロンプトで、
start IExplore.exe "about:<img src='http://...'>"
start "" "about:<img src='http://...'>"

アドレスバーは駄目です。

※IE7(?)/IE8では使えなくなりました。MSHTAなら使えます。

「ファイル名を指定して実行」に、
mshta about:<img src='http://...'>

コマンドプロンプトで、
start mshta.exe "about:<img src='http://...'>"

2007年3月26日 (月)

スクリプトで、PATHにないアプリを起動する。

PATHになくても、レジストリの
HKLM\Software\Microsoft\Windows\CurrentVersion\App Paths
キー配下に登録されていれば、WScript.ShellのRun()では、起動できますが、
Exec()は駄目。そういうときはフルパスをレジストリから取り出します。

Function GetPath(Name)
Dim wShell
Set wShell=CreateObject("WScript.Shell")
GetPath=wShell.RegRead("HKLM\Software\Microsoft\Windows\CurrentVersion\App Paths\"&Name&"\")
GetPath=Replace(GetPath,"""","")
GetPath=wShell.ExpandEnvironmentStrings(GetPath)
End Function

CreateObject("WScript.Shell").Exec """"&GetPath("acrord32.exe")&""""

2007年3月25日 (日)

環境に依存しないProgIDでCreateObject()するには?

CreateObject(ProgID)のProgIDは環境に依存して異なることがあって困ります。
そういうときは、一意なCLSIDを使えばよいわけですが。。。

例えば、"ScriptControl"、HTAやWSFなら、
<object classid=clsid:0E59F1D5-1FBE-11D0-8FF2-00A0D10038BC>
と、書けますが、CreateObject()の場合は?

Set wShell=CreateObject("WScript.Shell")
ProgID=wShell.RegRead("HKCR\CLSID\{0E59F1D5-1FBE-11D0-8FF2-00A0D10038BC}\ProgID\")
Set SC=CreateObject(ProgID)

一行では、
Set SC=CreateObject(CreateObject("WScript.Shell").RegRead("HKCR\CLSID\{0E59F1D5-1FBE-11D0-8FF2-00A0D10038BC}\ProgID\"))

関数化すると、
Function GetProgID(CLSID)
Dim wShell
Set wShell=CreateObject("WScript.Shell")
GetProgID=wShell.RegRead("HKCR\CLSID\{"&CLSID&"}\ProgID\")
End Function

Set SC=CreateObject(GetProgID("0E59F1D5-1FBE-11D0-8FF2-00A0D10038BC"))

2007年3月23日 (金)

バッチファイルからシフトキーの押し下げ状態を調べる。

@echo off
for /f "usebackq" %%0 in (`MSHTA.EXE "javascript:window.onunload=function(){new ActiveXObject('Scripting.FileSystemObject').GetStandardStream(1).WriteLine(this.event.shiftLeft);};close();resizeTo(0,0);"`) do set shiftkey=%%0
echo shiftkey is %shiftkey%

スクリプトからシフトキー類の押し下げ状態を調べる。

var ShiftKeys=new Array();
var fQuit=false;
var ie=new ActiveXObject("InternetExplorer.Application");
ie.Navigate("about:blank");
while(ie.Busy||ie.ReadyState!=4) WScript.Sleep(100);
ie.Document.body.onunload=OnUnload;
ie.Quit();
while(!fQuit) WScript.Sleep(100);
WScript.Echo(ShiftKeys.join(" + "));

function OnUnload(){
if(this.event.shiftLeft) ShiftKeys.push("shiftLeft");
if(this.event.shiftKey) ShiftKeys.push("shiftKey");
if(this.event.altLeft) ShiftKeys.push("altLeft");
if(this.event.altKey) ShiftKeys.push("altKey");
if(this.event.ctrlLeft) ShiftKeys.push("ctrlLeft");
if(this.event.ctrlKey) ShiftKeys.push("ctrlKey");
fQuit=true;
}

2007年3月18日 (日)

パイプの前後で遅延展開を使う。

パイプの前後の複文で遅延展開を使うにはどうするか?

CALLと%%を使う。^で変数名をエスケープします。^で^をエスケープします。

set aaa=111
(
set aaa=222
call echo %%^^aaa%%
)|more

CMD /V:ONを使う。^で!をエスケープします。

setlocal enabledelayedexpansion
set aaa=111
cmd /v:on /s /c "(set aaa=222 &echo ^!aaa^!)"|more

パイプの前後は子CMDプロセスで実行されます。

パイプの前後がどのように実行されているかは、
以下のバッチファイルを実行してみると分ります。

echo %%cmdcmdline%% >&2 | echo %%cmdcmdline%%

C:\WINDOWS\system32\cmd.exe /S /D /c" echo %cmdcmdline%"

複数行の複文は&で結合されて1行にされて実行されます。

(
echo %%cmdcmdline%%
echo %%cmdcmdline%%
)|more

C:\WINDOWS\system32\cmd.exe /S /D /c" ( echo %cmdcmdline% & echo %cmdcmdline% )"

FOR文のIN ('コマンド')も子CMDプロセスで実行されます。

for /f "delims=" %%1 in ('echo %%cmdcmdline%%') do echo %%1

C:\WINDOWS\system32\cmd.exe /c echo %cmdcmdline%

2007年3月16日 (金)

コマンドラインで、URLからHTMLソースを取り出す。

url2text.CMD URL >ファイル

@if(0)==(0) ECHO OFF
CScript.exe //NoLogo //E:JScript "%~f0" %1
GOTO :EOF
@end
var htmlfile=WScript.GetObject(WScript.Arguments.Item(0));
while(htmlfile.readyState!='complete') WScript.Sleep(100);
WScript.Echo(htmlfile.documentElement.outerHTML);

コマンドラインで、URLからテキストを取り出す。

url2text.CMD URL >ファイル

@if(0)==(0) ECHO OFF
CScript.exe //NoLogo //E:JScript "%~f0" %1
GOTO :EOF
@end
var htmlfile=WScript.GetObject(WScript.Arguments.Item(0));
while(htmlfile.readyState!='complete') WScript.Sleep(100);
WScript.Echo(htmlfile.body.innerText);

2007年3月13日 (火)

SendKeysでIMEをバイパスする。

IMEがオンの相手にSendKeysすると、かなに変換されちゃいます。

SendKeys "AAA" → あああ

これを避けるには、シフトキーを押しているとよいようです。

SendKeys "+(AAA)" → AAA

小文字を送りたいときは、

SendKeys "{CapsLock}+(AAA){CapsLock}" → aaa

※CapsLockでないときの話です。

2007年3月12日 (月)

If AndAlso や OrElse の代替方法

VB.NETには論理演算のAndAlsoとOrElseがあるけれど、
VBScriptにはないので、その代替方法。

If x AndAlso y AndAlso z Then 処理
の代わりに、

If x Then
  If y Then
    If z Then
      処理
    End If
  End If
End If

と書くと、ネストのインデントが深くなってやーです。
そういうときは、

If Not x Then
ElseIf Not y Then
ElseIf Not z Then
Else
  処理
End If

と書けばよさそうですが、Notを使ってよいのは、x、y、zがBooleanのときだけです

If x AndAlso y=p AndAlso z<>q Then 処理
なら

If x=0 Then
ElseIf y<>p Then
ElseIf z=q Then
Else
  処理
End If

のように書くとよいでしょう。

If x=y OrElse x=z Then 処理
の代替は、

Select Case x
Case y,z
  処理
End Select

If x<>y AndAlso x<>z Then 処理
の代替は、

Select Case x
Case y,z
Case Else
  処理
End Select

And Or Notを論理演算と思わないこと。

And Or Notを論理演算と思っていると嵌るので、ビット演算と思うべし。

If x Then If y Then が真でも、If x And y Then が真とは限らない。

If x And y Then で x が偽でも、y が評価実行される。

If x Or y Then で x が真でも、y が評価実行される。

If x Then が真でも、If Not x Then が偽とは限らない。

2007年3月11日 (日)

二つのテキストファイルの行同士を接合するバッチ その3

接合.CMD ファイル1 ファイル2

@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
(FOR /F %%0 IN ('FIND /C /V ""') DO SET a1=%%0) <%1
(FOR /F %%0 IN ('FIND /C /V ""') DO SET a2=%%0) <%2
IF %a1% LSS %a2% SET /A a1=a2
(FOR /L %%k IN (1,1,%a1%) DO (
SET s1=
SET s2=
SET /P s1= >NUL <&4
SET /P s2= >NUL <&5
ECHO:!s1! !s2!
)
) 4<%1 5<%2

横にタブで接合します。
縦に改行で接合するには、
ECHO:!s1!
ECHO:!s2!
に変えます。

2007年3月10日 (土)

二つのテキストファイルの行同士を接合するバッチ その2

接合.CMD ファイル1 ファイル2

@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
(FOR /F %%0 IN ('FIND /C /V ""') DO SET N1=%%0) <%1
(FOR /F %%0 IN ('FIND /C /V ""') DO SET N2=%%0) <%2
IF %N1% LSS %N2% SET /A N1=N2
SET /A N2=N1
SET N3=1
:L1
SET N2=%N2:~1%
SET /A N3*=10
IF DEFINED N2 GOTO L1
SET /A N4=N3+N1
(
@ECHO OFF
(FOR /F "DELIMS=[] TOKENS=1*" %%0 IN ('FIND /N /V ""') DO (
SET /A NN=N3+%%0 >NUL
CALL ECHO %%NN%% A %%1
)
) <%1
SET /A NN+=1 >NUL
FOR /F %%4 IN ('ECHO %%NN%%') DO FOR /L %%0 IN (%%4,1,%N4%) DO ECHO %%0 A
(FOR /F "DELIMS=[] TOKENS=1*" %%0 IN ('FIND /N /V ""') DO (
SET /A NN=N3+%%0 >NUL
CALL ECHO %%NN%% B %%1
)
) <%2
SET /A NN+=1 >NUL
FOR /F %%4 IN ('ECHO %%NN%%') DO FOR /L %%0 IN (%%4,1,%N4%) DO ECHO %%0 B
)|FOR /F "TOKENS=1-2*" %%1 IN ('SORT') DO @IF %%2==A (SET /P X=%%3 <NUL) ELSE ECHO:%%3

横にタブで接合します。
縦に改行で接合するには、
)|FOR /F "TOKENS=1-2*" %%1 IN ('SORT') DO @ECHO:%%3
に変えます。

2007年3月 9日 (金)

パイプと遅延展開、CALL :ラベル、@ECHO OFF、SET /Aとの相性

パイプと遅延展開の組み合わせが駄目です。

setlocal enabledelayedexpansion
(
set a=1
echo !a!
)|more

パイプとCALL :ラベルの組み合わせも駄目です。

call :sub | more
goto :eof
:sub
echo 1

パイプと@ECHO OFFの組み合わせも駄目です。

@echo off
(for %%0 in (1 2) do (
echo %%0
)
)|more

パイプとSET /Aの組み合わせも駄目です。

set /a x=1|more

これらは、パイプがなければ正常です。

パイプの前後は、そこだけ、cmd /c"~"で実行されてるような感じです。
バッチ内とは見做されないようです。なので、echo offの効果が及ばない。
バッチ外では、call :ラベルは使えない。set /aは結果がechoされる。
setlocal enabledelayedexpansionも無効。

2007年3月 8日 (木)

二つのテキストファイルの行同士を接合するバッチ

接合.CMD ファイル1 ファイル2

@if(0)==(0) ECHO OFF
CScript.exe //NoLogo //E:JScript "%~f0" %1 %2
GOTO :EOF
@end
var fso=new ActiveXObject('Scripting.FileSystemObject');
var f1=fso.OpenTextFile(WScript.Arguments.Item(0));
var f2=fso.OpenTextFile(WScript.Arguments.Item(1));
while(!f1.AtEndOfStream || !f2.AtEndOfStream){
  var s1=f1.AtEndOfStream?'':f1.ReadLine();
  var s2=f2.AtEndOfStream?'':f2.ReadLine();
  WScript.Echo(s1+'\t'+s2);
}

横にタブで接合します。
縦に改行で接合するには、'\n'に変えます。

2007年3月 7日 (水)

テキストファイルの何行目から何行目までを切り出すバッチ

切り出し.CMD 開始行 終了行 ファイル

@ECHO OFF
(FOR /F "delims=[] tokens=1*" %%0 IN ('FIND /N /V ""') DO (
IF %%0 GTR %2 GOTO :EOF
IF %%0 GEQ %1 ECHO=%%1
)
)<%3

或いは、

@ECHO OFF
SETLOCAL
(FOR /F %%n IN ('FIND /C /V ""') DO SET /A n=%%n-%2)<%3
SORT /+10000 %3 | MORE +%n% | SORT /+10000 | MORE +%1

2007年3月 6日 (火)

テキストファイルから、開始文字列~終了文字列の行を抜き出すバッチ

切り出し.CMD 開始文字列 終了文字列 ファイル

@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
(FOR /F "delims=[] tokens=1*" %%0 IN ('FIND /N /V ""') DO (
IF "!FLAG!"=="1" SET FLAG=2
IF "!FLAG!"=="3" SET FLAG=4
SET "LINE=%%1"
SET "LINE=!LINE:%1=!"
IF NOT "!LINE!"=="%%1" SET FLAG=1
SET "LINE=%%1"
SET "LINE=!LINE:%2=!"
IF NOT "!LINE!"=="%%1" SET FLAG=3
IF "!FLAG!"=="1" ECHO=%%1&rem ※開始行を含む/含まない
IF "!FLAG!"=="3" ECHO=%%1&rem ※終了行を含む/含まない
IF "!FLAG!"=="3" GOTO :EOF ※1区間限り/繰り返し
IF "!FLAG!"=="2" ECHO=%%1
)
)<%3

開始行、終了行を含み、1区間だけ、切り出します。
※の各行をコメントアウトすると、変更できます。

2007年3月 5日 (月)

For Index To Stepループの途中脱出の判定方法

インデクスの満了値(To+Step)を判定すれば確実ではありますが、
これもあまり好きではありません。

For Index=0 To Items.Count-1
  If Items(Index)... Then Exit For
Next
If Index<Items.Count Then 途中脱出

インデクスの満了値が0になるようにして、0判定にしたいところです。

For Index=Items.Count To 1 Step -1
  If Items(Index-1)... Then Exit For
Next
If Index>0 Then 途中脱出

For Each Inループの途中脱出の判定方法

フラグを立てれば確実ではありますが、そのためにフラグを作ったりなんのと、
あまり好きではありません。

Flag=False
For Each Item In Items
  If Item... Then
    Flag=True
    Exit For
  End If
Next
If Flag Then 途中脱出

ループ満了時のループ変数の設定値に関する仕様記述はありませんが、
経験的には、例外なく、Emptyです。

For Each Item In Items
  If Item... Then Exit For
Next
If TypeName(Item)="Empty" Then ループ満了

Itemがオブジェクトでなければ以下でも可。が、一般的には避ける。
If IsEmpty(Item) Then ループ満了

2007年3月 3日 (土)

環境変数のPATHを行分けして表示するバッチファイル(続々編)

バッチファイルの文字列操作例です。

@ECHO OFF
SETLOCAL
SET "PATH=%PATH:"=?%"
SET S=
:LOOP
SET "C=%PATH:~0,1%"
IF "%C%"==";" (
ECHO=%S:?="%
SET S=
) ELSE (
SET "S=%S%%C%"
)
SET "PATH=%PATH:~1%"
IF DEFINED PATH GOTO LOOP
IF DEFINED S ECHO=%S:?="%

ポイントは、
処理前に引用符を置換する。
SET "name=value" のようにエスケープする。
処理後に引用符を戻す。

ここではパス名に使えない文字 ? を使っているが、^E(\x05)のような制御文字も使えます。

2007年3月 2日 (金)

WSHの引数で二重引用符 " をエスケープするには?

WSHの引数では、二重引用符 " が消えます。エスケープ方法はありません。
なので代替文字を用います。
単一引用符 ' はJScriptが使用するので、逆引用符 ` を使うとよいでしょう。
引数の区切りの空白類をエスケープするためには、二重引用符も必要です。
そこで、二重引用符と逆引用符 ` をペアで用います。

"aaa bbb"を渡したいときは、"`aaa bbb`"や`"aaa bbb"`、"`aaa bbb"`のように
二重引用符の代わりに、二重引用符と逆引用符のペアを指定します。
いずれの場合も、WScript.Argumentsには、`aaa bbb`が渡ります。

2007年3月 1日 (木)

document.write()のセキュリティゾーン

about:blankを開くと、インターネットゾーンです。
そこにdocument.write()すると、どこになるでしょうか?
インターネットゾーンでしょうか?

いえいえ、document.write()した人のlocationとセキュリティゾーンになります。

例えば、WSHからdocument.write()すると、インターネットゾーンになります。

ローカルのHTMLファイルやHTAファイルからdocument.write()すると、
マイコンピュータゾーンになります。

この場合、スクリプトなどを書き込むと、
マイコンピュータゾーンのロックダウンが掛かります。

それを避けるには、document.write()などを使わないで、
元のページ内容をDOMで動的に変更するとよいでしょう。
innerHTML=
outerHTML=
insertAdjacentHTML
など

ただし、セキュリティレベルが高い場合は、オブジェクトやスクリプトを
組み込むことは出来ません。

その場合は自分側のオブジェクトやスクリプトを接続して使うとよいでしょう。
Set 相手先variable=自分側オブジェクト
Set 相手先id.onevent=GetRef("自分側proc")

« 2007年2月 | トップページ | 2007年4月 »