Excel VBA и командная строка Windows

Если я наберу это в командной строке Windows:

Find "Foo" "D:\test.txt" | ECHO %ERRORLEVEL%

Я получаю 9009 ‹--- это потому что он не был найден

Если я наберу это в командной строке Windows:

Find "End" "D:\test.txt" | ECHO %ERRORLEVEL%

Я получаю 0 ‹--- это потому что он был найден

Я хочу отправить эту команду из Excel VBA в командную строку Windows и получить ответ. Вот что я пробовал, и это не работает, но я чувствую, что это близко:

Sub test()

    Dim cmdLine As Object
    Dim result As String

    Set cmdLine = CreateObject("WScript.Shell")
    result = cmdLine.Exec("%comspec% /C Find ""End of Report"" ""D:\test.csv"" | ECHO %ERRORLEVEL%").STDOut.ReadAll

    Debug.Print (result)

End Sub

person XCELLGUY    schedule 11.03.2020    source источник
comment
Приведенный выше код постоянно возвращает 0   -  person XCELLGUY    schedule 11.03.2020
comment
Есть ли лучшее место, чтобы опубликовать это?   -  person XCELLGUY    schedule 11.03.2020
comment
Попробуйте Dim result As Variant и STDOut.ReadAll()?   -  person Chronocidal    schedule 11.03.2020
comment
Выдает тот же результат... который равен 0... если я изменю End of Report на Foo, он все равно вернет 0   -  person XCELLGUY    schedule 11.03.2020
comment
Я не могу подтвердить, что в случае Find "Foo" "D:\test.txt" | ECHO %ERRORLEVEL% получается 9009. Я всегда получаю 0 за Find "Foo" "D:\test.txt" | ECHO %ERRORLEVEL%и Find "End" "D:\test.txt" | ECHO %ERRORLEVEL%   -  person Storax    schedule 11.03.2020
comment
В основном... Насколько я понимаю, я должен получить 0, если он найден, и некоторое число больше 0 в противном случае. В моем примере... Он должен найти End, но не Foo... Однако они оба, кажется, возвращают 0   -  person XCELLGUY    schedule 11.03.2020
comment
Я не эксперт в пакетном программировании, я просто говорю, что команда Find возвращает 0 на моем компьютере в обоих случаях, и кажется, что и на вашем компьютере тоже.   -  person Storax    schedule 11.03.2020
comment
О, я понимаю...   -  person XCELLGUY    schedule 11.03.2020


Ответы (1)


Прежде всего, вам может потребоваться дождаться, пока wscript завершит выполнение команды, поэтому я бы попробовал что-то вроде этого

Sub test()

    Dim cmdLine As Object
    Dim result As Object

    Set cmdLine = CreateObject("WScript.Shell")

    Set result = cmdLine.Exec("%comspec% /C Find ""End of Report"" ""D:\test.csv"" | ECHO %ERRORLEVEL%")

    Do While result.Status = 0
        Application.Wait Now + TimeValue("00:00:01")
    Loop


    Debug.Print result.stderr.readall(), result.stdout.readall()

End Sub

Чтобы убедиться, что команда действительно работает, вы можете удалить ECHO %ERRORLEVEL%, и вы действительно получите stdout соответственно. stderr.

Sub testA()

    Dim cmdLine As Object
    Dim result As Object

    Set cmdLine = CreateObject("WScript.Shell")

    Set result = cmdLine.Exec("%comspec% /C Find ""End of Report"" ""D:\test.csv""")

    Do While result.Status = 0
        Application.Wait Now + TimeValue("00:00:01")
    Loop


    Debug.Print result.stderr.readall(), result.stdout.readall()

End Sub

Обновление: если вам нужно найти только определенный текст в файле, вы можете использовать следующий подход.

Sub TestC()
    Debug.Print inFile("D:\Test.csv", "End of Report")
End Sub

Function inFile(fileName As String, searchText As String) As Boolean

    Dim fileContent As String
    Dim fileNo As Long
    fileNo = FreeFile
    Open fileName For Input As #fileNo
    fileContent = Input(LOF(fileNo), fileNo)
    Close #fileNo

    If InStr(1, fileContent, searchText, vbTextCompare) > 0 Then
        inFile = True
    Else
        inFile = False
    End If

End Function

Обновление 2. Судя по комментариям, решение вашей проблемы может быть следующим.

Sub TestD()
    Dim fileName As String
    fileName = "D:\Test.csv"
    If Not IsFileOpen(fileName) Then
        Debug.Print inFile(fileName, "End of Report")
    End If
End Sub

Function inFile(fileName As String, searchText As String) As Boolean

    Dim fileContent As String
    Dim fileNo As Long
    fileNo = FreeFile
    Open fileName For Input As #fileNo
    fileContent = Input(LOF(fileNo), fileNo)
    Close #fileNo

    If InStr(1, fileContent, searchText, vbTextCompare) > 0 Then
        inFile = True
    Else
        inFile = False
    End If

End Function


Function IsFileOpen(fileName As String)
    Dim filenum As Integer, errnum As Integer

    On Error Resume Next   ' Turn error checking off.
    filenum = FreeFile()   ' Get a free file number.
    ' Attempt to open the file and lock it.
    Open fileName For Input Lock Read As #filenum
    Close filenum          ' Close the file.
    errnum = Err           ' Save the error number that occurred.
    On Error GoTo 0        ' Turn error checking back on.

    ' Check to see which error occurred.
    Select Case errnum

        ' No error occurred.
        ' File is NOT already open by another user.
        Case 0
         IsFileOpen = False

        ' Error number for "Permission Denied."
        ' File is already opened by another user.
        Case 70
            IsFileOpen = True

        ' Another error occurred.
        Case Else
            Error errnum
    End Select

End Function
person Storax    schedule 11.03.2020
comment
Я скопировал первый фрагмент кода и вставил его... без изменений... но он снова вернул 0... Я изменил End of Report на Hello, который он не должен найти... но все равно вернул 0 - person XCELLGUY; 11.03.2020
comment
он возвращает только один 0... если это что-то значит... - person XCELLGUY; 11.03.2020
comment
Да, как я уже сказал в своем комментарии выше, кажется, что errorlevel всегда 0. Если вы попробуете второй код в сообщении, вы увидите, что вы действительно получите stdout. Итак, похоже, что ind ""End of Report"" ""D:\test.csv"" | ECHO %ERRORLEVEL% является нарушителем спокойствия. - person Storax; 11.03.2020
comment
Я в замешательстве... Я в основном пытаюсь получить истину/ложь или 1/0... - person XCELLGUY; 11.03.2020
comment
Да, это правильно, но он возвращает стандартный вывод, верно? Я обновлю сообщение с другим подходом, если вам нужно только искать в файле определенную строку. - person Storax; 11.03.2020
comment
Обновленный код открывает файл, это правильно? Я считаю, что мне нужно решение, которое не требует открытия файла. - person XCELLGUY; 11.03.2020
comment
Правильно, он откроет файл, прочитает его содержимое в строку, а затем закроет его. Find также откроет файл. Вы не можете найти что-то в файле, не открывая его. - person Storax; 11.03.2020
comment
хм... Я понимал, что запуск команды find из командной строки на самом деле не открывает файл... этот файл может быть не завершен, потому что он автоматически генерируется машиной. Машина выгружает текст в файл партиями. Одна из последних строк текста — «Конец отчета». Я ищу эту фразу, чтобы определить, завершен файл или нет. Можно ли открыть этот файл до того, как он будет закончен? Может ли это вызвать проблемы? - person XCELLGUY; 11.03.2020
comment
Это зависит! Приведенный выше код открывает файл для чтения, и если машина, создающая файл, заблокировала файл для записи и чтения, это может вызвать проблему. Но тогда find тоже не запустится. - person Storax; 11.03.2020
comment
насколько я понимаю, файл заблокирован, но проблема, которую я изначально пытался решить, заключалась в том, что когда я использую команду open в excel vba для открытия текстового файла... глупо знать, что он заблокирован и открывает наполовину завершенный текстовый файл ... Это можно продемонстрировать, попытавшись открыть его с помощью блокнота по сравнению с MS Word ... MS Word скажет, что он заблокирован, тогда как блокнот не будет, потому что блокнот тупой ... Насколько я понимаю, эта блокировка находится в операционной системе Windows. .. не свойственный самому файлу. Итак ... в идеале ... я хочу проверить, заблокирован ли файл, но не смог понять это - person XCELLGUY; 11.03.2020
comment
Если вам просто нужно узнать, заблокирован ли файл, то здесь есть вопросы по этой теме. Например: stackoverflow.com/questions/12300678/ Но, может быть, ваш код для написания отчетов блокирует файл только во время записи пакета данных? - person Tim Williams; 11.03.2020