dポイントプレゼントキャンペーン実施中!

Excel VBA コマンドライン(MS-DOS)でウィンドウを閉じずに最終行(文字)まで取得する。

コマンドライン上で実行した結果を受け取って入力待ち状態のところまで読み込み、そのコマンドラインウィンドウ上で次のコマンドを入力したい。
Wscript.Exec.Stdout で標準出力を取得するものの、ウィンドウが開きっぱなしなので、EOSにならないため、Do~Loopで取得すると、最終行を取得する又は最後の文字+1文字を取得する時に、続きを待つためにフリーズする。
何か良い手はないでしょうか?
(諸般の事情については後述します)

sample - - - - - - - - - - - - - - - - - -
Dim wsh As Object
Dim wExec As Object
Dim buf as string

Set wsh = CreateObject("Wscript.Shell")
Set wExec = wsh.exec("%ComSpec% /c CMD")
wExec.stdin.Write "dir" & vbCrLf
Do Until wExec.stdout.AtEndOfStream
buf = buf & wExec.stdout.Read(1)
Loop
- - - - - - - - - - - - - - - - - -
 dir コマンド実行後、カレントフォルダ>までは読み込むが、次がないので読み込み状態で止まる。

■試したこと
 CMD実行時、リダイレクトで標準出力結果をtxtに出力する。
 txtの容量をモニターして、任意の時間(1秒未満)、更新がなければ次の処理判定をする
 ⇒dir c:\ /s を実行したら、対象が多すぎたのかtxtの容量が途中で増えなくなった。
  (ウィンドウを閉じたら更新された)
 今のところ、一番近い動作ができそうなのはこの方法ですが、
 上記から、txt ファイルの更新が完全なリアルタイムではないようなので、できるだけ標準出力を直接読み取りたく、次点としています。
- - - - - - - - - - - - - - - - - -
  Set wExec = wsh.exec("%ComSpec% /c CMD > C:\log.txt")
wExec.stdin.Write "dir c:\ /s" & vbCrLf
for n = 1 to 1000
debug.print FileLen("C:\log.txt")
sleep 10
DoEvents
next n
~~
- - - - - - - - - - - - - - - - - -

■実際にやりたいこと(事情)
PLINK (telnet) コマンドでアクセスした先とのやり取りを自動化したい。
コマンドによっては、環境によって、その後実行するコマンドが可変になるため、
入力待ち状態で、それまで出力された情報を読み取って、処理を決定したい。
中断すると、コマンド入力が始めからになるので、ウィンドウはひらきっぱなしにしたい。
サーバー側の挙動は変えられない。
追加のフリーソフトなどの導入はNG。

以上、よろしくお願いいたします。

A 回答 (5件)

> ASTERACEAE は適当な文字列ですよね。



はい。ここでは応答が定数のコマンドを投入して楽をしていますが、1文字ずつ読み込みながら読み込みすぎてブロックされてしまう前に先行のコマンドの応答を解析して次のコマンドを投入していくことになると思います。

ブロックされないことを確認してから読みこむには CreateProcess() に CreatePipe() を接続して PeekNamedPipe() します。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。

>ブロックされないことを確認してから読みこむには CreateProcess() に CreatePipe() を接続して PeekNamedPipe() します。

これは・・・すみません、私の実力では全くついていけないないようですね。
勉強します・・・が、使い方について、参考にできるようなページはあるでしょうか?

とっかかりすらうまくつかめません・・・

お礼日時:2018/05/09 21:34

VBA + CreateProcess + CreatePipe + PeekNamedPipe を検索すると見つかります:

https://qiita.com/shela/items/4340c5f234911db7cf9c これらは Win32 API です。Win32 API のリファレンスは C/C++ で解説しているので、これらを正しく使うには C/C++ と VBA を相互に翻訳できる必要があります。ブロックされない読みこみが本質的に必要なのでしょうか? なぜでしょうか。
    • good
    • 0
この回答へのお礼

返答が遅くなり申し訳ありません。
ご紹介いただいたPageを読み込んでみます。


事情について、良い例が出せないのですが、
質問文末尾内容 に補足するなら
すでに作りこまれて変更できないシステムに対して、
コマンド実行後、いろいろな入力を求められるのですが、
直前の表示が不定なので、標準出力文字で判定ができないといったところでしょうか。

dir /p だと、末尾まで、何度 Enter Key を押せばいいかわからない・・・
のような。(実際に vba から dir /p しても /p は無視されるみたいなので良い例ではないですが。)

お礼日時:2018/05/13 11:17

入力待ちになる前に次のコマンドを投入します



Set wExec = wsh.exec("%ComSpec%") ' cmd.exe
wExec.stdin.Writeline "dir"
wExec.stdin.Writeline "echo ASTERACEAE"
s = 1
Do Until wExec.stdout.AtEndOfStream
 buf = wExec.stdout.Readline
 Debug.Print buf
 If buf Like "ASTERACEAE*" Then
  Select Case s
  Case 1
   wExec.stdin.Writeline "cd .."
   wExec.stdin.Writeline "echo ASTERACEAE"
   s = 2
  Case 2
   wExec.stdin.Writeline "exit"
   s = 3
  End Select
 End If
Loop
    • good
    • 0
この回答へのお礼

なるほど!
ASTERACEAE は適当な文字列ですよね。
直前のコマンドが終了したら、echoで固定の値が出力されるようにして、それを取ると。

ありがとうございます。

質問文、sample コードに対しては問題ありませんので、私が悪いのですが、
「任意の入力待ちが発生するコマンドの実行中」で実行できるような手段はあるでしょうか?

よろしくお願いいたします。

お礼日時:2018/05/07 21:48

質問文ちゃんと読んでませんでした、先の回答は気にしないでください

    • good
    • 0
この回答へのお礼

コメントありがとうございます。

お礼日時:2018/05/07 00:03

コマンドプロンプトを開く時に /k オプションを付ければいいのではないですか?

    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!