- Сообщения
- 8,030
- Решения
- 14
- Реакции
- 6,805
Статья от 17.01.2013
Автор: Dragokas
Автор: Dragokas
Принцип составления однострочных команд Batch
Однострочные команды Batch используются там, где нет возможности написать команды
в несколько строк, в случаях когда они объединены логикой и не могут выполнятся в разрыве друг от друга в разных сессиях интерпретатора.
Область применения:
1) Языки программирования высокого уровня
2) Реестр Windows (reg-файл)
Пример логики связи:
1) Команды "удалить файлы a и b"
CMD/BATCH:
del a
del b
VB.NET / VBA:
shell "cmd /c del a"
shell "cmd /c del b"
CMD/BATCH:
Set /A n= 1 + 1
Echo %n%
Чтобы составить сложный набор однострочных команд для выполнения в методе (процедуре, объекте) Shell другого ЯП
нужно сначала добиться успешной отработки Вашей конструкции в среде командного интерпретатора.
Открываем консоль - Win + R (выполнить), CMD {Enter}
Формируем однострочные команды, подставляя первой командой запуск самого EXE-файла интерпретатора:
CMD/BATCH:
CMD.exe /C Echo Привет
а сами команды разделяются знаком "амперсанд" (&)
CMD/BATCH:
::если файл "а" существует, скопировать его под именем "b". Удалить файл "c".
cmd /c "if exist a copy a b& del c"
CMD/BATCH:
::Например, копирование файла с пробелами в пути и/или имени:
cmd /c "copy "c:\my folder\a.txt" "c:\my folder\b.txt""
Если участвует цикл FOR, в отличие от текста bat-файла, здесь спецсимволы не обрабатываются, поэтому % в цикле удваивать не нужно.
Если команду нужно указать вне цикла, тогда весь блок цикла помещается в скобки.
CMD/BATCH:
::Подсчет кол-ва файлов *.txt
cmd /c "(for %a in (*.txt) do set /A n+=1)& Echo !n!"
CMD/BATCH:
cmd /c "for %a in (*.txt) do (set /A n+=1& Echo !n!)"
CMD/BATCH:
cmd /c "SetLocal EnableDelayedExpansion& Set /A n= 1 + 1& Echo !n!"
CMD/BATCH:
cmd /v:on /c "Set /A n= 1 + 1& Echo !n!"
Построение кавычек внутри переменных других ЯП
Кавычка (") - является специальным (служебным) символом для языка Visual Basic,
и если в реестре, или в языках C++, C# ... для задания кавычки (") как значение переменной нужно указать экран в виде бекслеша (\)
[csharp=-1]st = "\""[/csharp]
в VB кавычка удваивается.
Есть 2 способа присвоения значений с кавычкой переменной:
1) Удвоение кавычки
VB.NET / VBA:
Shell = "cmd /c ""copy ""c:\my folder\a.txt"" ""c:\my folder\b.txt"""""
2) Через функцию Chr(34), которая возвращает символ под номером 34 ASCII-таблицы кодов (").
В VB результат выполнения функции и строковой тип данных может конкатенироваться знаком амперсанд (&).
VB.NET / VBA:
Shell = "cmd /c " & Chr(34) & "copy " & Chr(34) & "c:\my folder\a.txt" & Chr(34) & " " & Chr(34) & "c:\my folder\b.txt" & string(2, Chr(34))
Общий принцип разбора чужих запросов с кавычками таков:
Вариант 1) Автоматически.
Поставьте Stop после команды присвоения переменной сложного запроса.
выполните ?variable {ENTER} в окне Immediate (Вид - окно неотложного (View - Immediate (Ctrl+G)))
Вариант 2) Вручную.
Кавычка в CMD - это двойная кавычка здесь в переменной ""), т.е. если видите запись вида:
VB.NET / VBA:
param = """ """
CMD/BATCH:
" "
Также в реестре, C++, C# ... спецсимволом является сам знак бекслеш (\), который разделяет папки, путь к файлу.
Здесь приняты 2 способа:
1) Удвоение бекслеша (\\)
2) Замена бекслеша (\) на обычный слеш (/)cs_compile.reg написал(а):[HKEY_CLASSES_ROOT\VisualStudio.cs.11.0\shell\compile\command]
@="\"c:\\Program Files (x86)\\hidcon.exe\" \"c:\\Program Files (x86)\\ModsCompiler.bat\" \"%1\""
cs_compile.reg написал(а):@="cmd /c \"\"c:/Program Files (x86)/ModsCompiler.bat\" \"%1\"\""
Альтернативой для ЯП при использовании Shell является выгрузка кода в несколько строк во внешний файл. Запуск его отдельно.
При этом такой код может быть заранее:
1) записан в переменную по указанным выше правилам.
Код от INV.DS
VB.NET / VBA:
'Запись:
'Для записи текста служит функция Print(и Write)
Open "c:\1.txt" For Append As #1 'Открываем файл для добавления записи, с номером канала Print #1, "Твой ТЕКСТ"' Записываем в файл 1.txt текст
Close #1 'Закрываем файл
'Есть еще функция для определения свободного канала - FreeFile. Например:
f = FreeFile 'Возвращает номер свободного канала
Open "c:\1.txt" For Append As f 'Открываем файл для добавления записи
Print #f, "Твой ТЕКСТ"'Записываем в файл 1.txt текст
Close #f 'Закрываем файл
'Чтение:
'Считать данные из файла сложнее чем записать. Есть два способа чтения данных из файла. Первый:
f = FreeFile
Open "c:\1.txt" For Input As f' Открываем файл 1.txt для чтения
Text1.Text = Input(LOF(f), f) 'Считываем текст из открытого файла в текстовое поле(Оператор LOF(Len Of File) определяет длину файла)
Close f
'Второй:
Dim txt as String
Open "c:\1.txt" For Input As #1' Открываем файл 1.txt для чтения
Do While Not EOF(1) ' Функция EOF(End Of File) проверяет, достигнут ли конец файла Line Input #1, txt ' Читаем строку данных Text1.Text = txt
Loop
Close #1
Руководство от Alex77755
Код VB6 от Catstail
Вот комментированный код запуска файла, хранящегося в теле другого файла:
А вот комментированный код exe-мэйкера:
Вот комментированный код запуска файла, хранящегося в теле другого файла:
VB.NET / VBA:
Private Sub Command1_Click()
'::: Определяем домашнюю директорию
HomeDir$ = App.Path
'::: Берем свободный номер файла
fi% = FreeFile
'::: Открываем сами себя на чтение в двоичном доступе
Open HomeDir$ + "\" + App.EXEName + ".exe" For Binary Access Read As #fi%
'::: Определяем собственную длину
LF& = LOF(fi%)
'::: Позиционируем файловый указатель на начало последних
'::: 4-x байтов EXE
Seek #fi%, LF& - 3
'::: Читаем длину тела запускаемого файла
Get #fi%, , Offset&
'::: Позиционируем файловый указатель на начало
'::: тела запускаемого файла
Seek #fi%, LF& - Offset& - 3
'::: Создаем буфер для тела запускаемого файла
Buf$ = Space$(Offset&)
'::: Читаем тело
Get #fi%, , Buf$
'::: Закрываем входной файл
Close #fi%
'::: Берем свободный номер файла
fo% = FreeFile
'::: Открываем в тек. директории файл с каким-либо именем
Open HomeDir$ + "\notepad.sss" For Binary Access Write As #fo%
'::: Сбрасываем в файл содержимое
Put #fo%, , Buf$
'::: Закрываем
Close #fo%
'::: Скрываем форму
Me.Hide
'::: Запускаем... и ждем завершения
Processn.ExecPrg HomeDir$ + "\notepad.sss", "", RC%, vbNormalFocus
'::: Дождались - покажем форму
Me.Show
'::: Удалим запускаемый файл
Kill HomeDir$ + "\notepad.sss"
'::: Покажем код завершения
MsgBox "RC=" + CStr(RC%)
End Sub
А вот комментированный код exe-мэйкера:
VB.NET / VBA:
Sub Main()
'::: Домашняя директория
HomeDir$ = App.Path
'::: Командная строка
CMD$ = Command$
'::: положение пробела в ком. строке
k% = InStr(CMD$, " ")
'::: нет пробела - ошибка
If k% = 0 Then
MsgBox "Запуск: maker Главный Запускаемый"
Exit Sub
End If
'::: первый параметр - имя главного файла
master$ = Left$(CMD$, k% - 1)
'::: второй параметр - имя запускаемого из
slave$ = Mid$(CMD$, k% + 1)
'::: Свободный номер файла
fi% = FreeFile
'::: Открываем главный (для чтения и записи!)
Open HomeDir$ + "\" + master$ For Binary Access Read Write As #fi%
'::: Получаем длину
LFM& = LOF(fi%)
'::: Свободный номер файла
ffi% = FreeFile
'::: открываем подчиненный (только для чтения)
Open HomeDir$ + "\" + slave$ For Binary Access Read As #ffi%
'::: Получаем длину
LFS& = LOF(ffi%)
'::: создаем буфер для запускаемого файла
BufS$ = Space$(LFS&)
'::: Читаем весь запускаемый файл в буфер
Get #ffi%, , BufS$
'::: Позиционируем главный файл в конец
Seek #fi%, LFM& + 1
'::: Выводим буфер
Put #fi%, , BufS$
'::: выводим длину (чтобы главный мог узнать, сколько байтов от конца нужно взять)
Put #fi%, , LFS&
'::: Все закрываем
Close
'::: OK!
MsgBox "OK!"
End Sub
1) Рекурсивный подсчет кол-ва файлов, заданных маской
VB.NET / VBA:
Sub CMD_Seek_Recursive()
Dim RetCode, Query As String, StartFolder As String, SeekFile As String, Flags As String
Dim isRecursive As Boolean
Dim inclSystem As Boolean
Dim inclHidden As Boolean
Dim inclReadOnly As Boolean
'Папка, начиная с которой ведется поиск
StartFolder = "l:\bash\test"
'Имя искомого файла (допускается подстановочный знак *)
SeekFile = "*.txt"
'Options
'Включить рекурсию
isRecursive = True
'Включить в поиск системные, скрытые файлы, только для чтения
inclSystem = True
inclHidden = True
inclReadOnly = True
Flags = IIf(isRecursive, "/s", "") + "/a:-D" + _
IIf(inclSystem, "", "-S") + IIf(inclHidden, "", "-H") + IIf(inclReadOnly, "", "-R")
Query = "cmd.exe /Q /V:on /C ""(for /f ""delims="" %x in ('dir /b " & Flags & " " & _
"""" & StartFolder & "\" & SeekFile & """') do (set /a n+=1))& Exit !n!"""
RetCode = CreateObject("WScript.Shell").Run(Query, 0, True)
Debug.Print "Количество найденных файлов = " & RetCode
End Sub
И чуть по-меньше буков:
VB.NET / VBA:
Sub CheckCount()
Debug.Print Get_Count_Files("l:\bash\test", "*.txt")
End Sub
'Выдает кол-во файлов SeekFile в папке StartFolder рекурсивно без учета скрытых файлов
Function Get_Count_Files(StartFolder As String, SeekFile As String) As Long
Get_Count_Files = CreateObject("WScript.Shell").Run("cmd /V:on /C ""(for /R """ & _
StartFolder & """ %x in (""" & SeekFile & """) do set /a n+=1)& Exit !n!""", 0, True)
End Function
Метод от Казанский
Получение ErrorLevel из команды CMD в переменную VBS-скрипта
(на примере команды сравнения файлов)
Комментарий Dragokas:
Добавлю от себя: чтобы симитировать свой произвольный код возврата, достаточно указать команду Exit <code>
Например,
Получение ErrorLevel из команды CMD в переменную VBS-скрипта
(на примере команды сравнения файлов)
VB.NET / VBA:
Function FileCompare(path1, path2)
'возвращает результат двоичного сравнения двух файлов
'с помощью системной утилиты fc.exe. Возвращаемое значение:
'0 - файлы одинаковы;
'1 - файлы различаются;
'2 - файл не найден
FileCompare = CreateObject("wscript.shell").Run( _
"cmd /c fc /b """ & path1 & """ """ & path2 & """", 0, True)
End Function
Комментарий Dragokas:
Добавлю от себя: чтобы симитировать свой произвольный код возврата, достаточно указать команду Exit <code>
Например,
VB.NET / VBA:
'Двоичный сдвиг 0110(6) -> 0011(3)
FileCompare = CreateObject("wscript.shell").Run( _
"cmd /v:on /c set /A x=6"">>""1& exit !x!", 0, True)
Последнее редактирование: