使用脚本控制外部流程-CMD

介绍。

许多人问我是否可以从Access中控制外部过程。 通过外部进程,我说的是在Access外部运行脚本。 这将包括BAT,CMD和PowerShell脚本,甚至包括使用Windows的FTP.EXE命令行界面的FTP脚本。

这些脚本接口的功能很难加以限制。 CMD.EXE尤其可以控制几乎所有命令的整个脚本文件。 可以在Access中实现自动化。

这种脚本的我最喜欢的用途之一是升级项目的当前版本。 我会在启动时自动更新前端数据库,并且还提供了一个选项,可以在以后损坏时随时进行升级(不幸的是,某些Access数据库很容易出现)。

这就是我将在本文中解释的内容。 在同一主题领域中的另一个是

使用Scripts-FTP控制外部进程总体概念。

这个概念依赖于一个表,最简单地说,它设计为:

表格= [ tblCMD ]
 Field Name  Type        PK (Compound) 
Template    Boolean     #1
Type        String(1)   #2
LineNo      Long        #3
Cmd         String(255)
在某些情况下,我在此数据库升级CMD脚本中遇到了问题,单行中的命令长度可能超过允许的255个字符。 因此,在这种情况下,在我所附的示例中,我使用两个字段[Cmd1]和[Cmd2]代替了单个[Cmd]。

在处理要输入到脚本表中的数据时,要记住的一个非常重要的观点是,数据中具有可替换参数的能力带来了额外的功能。 在我的示例中,我使用百分比(%)后跟两个字母字符来标记数据中要从代码中插入值的点。 升级CMD脚本的示例是%Ac,它用于Access可执行文件的全名。 FTP脚本的用法不同,因此请注意不要混淆两者。 这是升级CMD脚本替换以及FTP脚本使用的值的列表。 替换参数与其相关变量具有相同的名称,除了%替换str。 所以,

代码中的strBa用于替换数据中%Ba的出现。

下一步是为同一表中的特定脚本创建模板的更新副本。 由于[Template]值为False,因此可以识别此新数据。 更新将用其必需的值替换前面提到的参数。 然后(通过查询)将此新数据(仅)导出到脚本文件。导出后,该数据将从表中删除。

完成所有操作并准备好脚本文件后,我们需要调用它。

示例数据。 表格= [ tblCMD ]
 Template  Type  Order  Cmd1                            Template  Type  Order  Cmd1 
  TRUE     U      10   @ECHO OFF                         FALSE    U      10   @ECHO OFF
  TRUE     U      20   IF NOT EXIST "%Fo\%Ba" GOTO RENAMEBACKUP
                                                         FALSE    U      20   IF NOT EXIST "D:\Scratch\Access\ControlExternalProcesses\ContEx_Last.Accdb" GOTO RENAMEBACKUP
  TRUE     U      30   ATTRIB -R "%Fo\%Ba" >NUL          FALSE    U      30   ATTRIB -R "D:\Scratch\Access\ControlExternalProcesses\ContEx_Last.Accdb" >NUL
  TRUE     U      40   DEL "%Fo\%Ba" >NUL                FALSE    U      40   DEL "D:\Scratch\Access\ControlExternalProcesses\ContEx_Last.Accdb" >NUL
  TRUE     U      50   IF ERRORLEVEL 1 GOTO BADBACKUP    FALSE    U      50   IF ERRORLEVEL 1 GOTO BADBACKUP
  TRUE     U      60   :RENAMEBACKUP                     FALSE    U      60   :RENAMEBACKUP
  TRUE     U      70   ECHO Attempting to rename '%Fo\%Or' to '%Ba'
                                                         FALSE    U      70   ECHO Attempting to rename 'D:\Scratch\Access\ControlExternalProcesses\ContEx.Accdb' to 'ContEx_Last.Accdb'
  TRUE     U      80   ECHO Needs "%Fo\%Or" to be closed before continuing...
                                                         FALSE    U      80   ECHO Needs "D:\Scratch\Access\ControlExternalProcesses\ContEx.Accdb" to be closed before continuing...
  TRUE     U      90   :START                            FALSE    U      90   :START
  TRUE     U     100  REN "%Fo\%Or" "%Ba" >NUL           FALSE    U     100   REN "D:\Scratch\Access\ControlExternalProcesses\ContEx.Accdb" "ContEx_Last.Accdb" >NUL
  TRUE     U     110  IF ERRORLEVEL 1 GOTO START         FALSE    U     110   IF ERRORLEVEL 1 GOTO START
  TRUE     U     120  ATTRIB +R "%Fo\%Ba" >NUL           FALSE    U     120   ATTRIB +R "D:\Scratch\Access\ControlExternalProcesses\ContEx_Last.Accdb" >NUL
  TRUE     U     130  ECHO Attempting to copy '%Ne' to '%Fo\%Or'
                                                         FALSE    U     130   ECHO Attempting to copy 'D:\Scratch\Access\ControlExternalProcesses\Release\ContEx01.00.00.Accdb' to 'D:\Scratch\Access\ControlExternalProcesses\ContEx.Accdb'
  TRUE     U     140  COPY /B /V /Y "%Ne" "%Fo\%Or" >NUL FALSE    U     140   COPY /B /V /Y "D:\Scratch\Access\ControlExternalProcesses\Release\ContEx01.00.00.Accdb" "D:\Scratch\Access\ControlExternalProcesses\ContEx.Accdb" >NUL
  TRUE     U     150  IF ERRORLEVEL 1 GOTO BADCOPY       FALSE    U     150   IF ERRORLEVEL 1 GOTO BADCOPY
  TRUE     U     160  ATTRIB -R -S -H "%Fo\%Or" >NUL     FALSE    U     160   ATTRIB -R -S -H "D:\Scratch\Access\ControlExternalProcesses\ContEx.Accdb" >NUL
  TRUE     U     170  IF ERRORLEVEL 1 GOTO BADCOPY       FALSE    U     170   IF ERRORLEVEL 1 GOTO BADCOPY
  TRUE     U     180  ECHO Restarting Access with the updated file.
                                                         FALSE    U     180   ECHO Restarting Access with the updated file.
  TRUE     U     190  START "Dummy Title" /D"%Fo" "%Ac"
[Cmd2]                "%Fo\%Or" ;%BE
                                                         FALSE    U     190   START "Dummy Title" /D"D:\Scratch\Access\ControlExternalProcesses" "C:\Program Files (x86)\Microsoft Office\Office14\MSAccess.Exe"
[Cmd2]                                                                        "D:\Scratch\Access\ControlExternalProcesses\ContEx.Accdb" ;
  TRUE     U     200  GOTO CMDEND                        FALSE    U     200   GOTO CMDEND
  TRUE     U     210  :BADBACKUP                         FALSE    U     210   :BADBACKUP
  TRUE     U     220  ECHO Unable to delete existing backup file '%Fo\%Ba'.
                                                         FALSE    U     220   ECHO Unable to delete existing backup file 'D:\Scratch\Access\ControlExternalProcesses\ContEx_Last.Accdb'.
  TRUE     U     230  GOTO CMDERROR                      FALSE    U     230   GOTO CMDERROR
  TRUE     U     240  :BADCOPY                           FALSE    U     240   :BADCOPY
  TRUE     U     250  ECHO Unable to copy '%Ne' to '%Fo\%Or' successfully.
                                                         FALSE    U     250   ECHO Unable to copy 'D:\Scratch\Access\ControlExternalProcesses\Release\ContEx01.00.00.Accdb' to 'D:\Scratch\Access\ControlExternalProcesses\ContEx.Accdb' successfully.
  TRUE     U     260  :CMDERROR                          FALSE    U     260   :CMDERROR
  TRUE     U     270  ECHO Please refer this problem to Support.
                                                         FALSE    U     270   ECHO Please refer this problem to Support.
  TRUE     U     280  PAUSE                              FALSE    U     280   PAUSE
  TRUE     U     290  :CMDEND                            FALSE    U     290   :CMDEND
  TRUE     U     300  DEL "%Fo\UPGRADE.CMD" >NUL         FALSE    U     300   DEL "D:\Scratch\Access\ControlExternalProcesses\UPGRADE.CMD" >NUL
注意 左边的数据是原始模板数据。 右边的数据是更新后的数据,这就是为创建实际脚本文件而导出的数据。 数据说明。

这是一个CMD脚本,在Access数据库随后关闭之前,Access代码将很快(但延迟很小)调用它。 总体目的是用新版本替换Access数据库文件,然后像旧文件一样调用新文件。 为了安全起见,当前文件将以相同的名称保存,但要附加“ _Last”。 如果有任何问题,只需在新文件上重命名即可重新启用该文件。

许多生产线对于整个过程而言都不那么重要,它们仅仅是为了提供尽可能可靠的过程。 我将解释限于基本原则。

  1. 第20行到第50行确保在重命名现有的_Last文件之前,将其删除。
  2. 从#60行到#110行尝试将当前文件重命名为_Last文件。
    仅当当前文件成功关闭后,此功能才能起作用。 这个过程会不断尝试,直到成功为止。
    此概念的另一个变体是简单地在循环中将文件重命名为其自身。 一旦成功,您就知道该文件是免费的。
  3. 从#120行到#170行复制文件的新版本来代替当前版本。
  4. 从#180行到#190行再次将Access重新启动,直接进入当前数据库。
    它使用[Cmd2],因为它还将参数传递给数据库,告诉数据库要链接到的后端文件。 通常不需要这样做,但这说明了如何做到这一点。
  5. 从#210行到#280行处理错误情况。
  6. #290和#300行通过删除脚本文件并结束来结束该过程。
码。

虽然我展示的某些代码行将引用我自己的一些例程,但这只是代码的一小部分,即使未显示代码,也应很清楚它的作用。 因此,我将展示和解释主要代码,并将整个数据库包括在附件中,以便在需要时可以探索其他任何例程。 如果需要,我的代码始终可以重复使用。 我唯一声称的是版权。 其他人可以自由使用和更改代码。

我先解释一下

MultiReplace()是我的功能之一,它通过允许多对from和to替换而简单地扩展了VBA.Replace()函数。 不过,我不在SQL中使用此功能,正如您从第26行至第37行的Replace()函数调用的笨拙用法中所看到的那样。 这是替换参数的地方。 要查看其效果,请在第60行上放置一个断点,并在代码中的该位置打印strSQL的值。

我已经包含了

下面的SetStrings() 。 它基本上用于获取我们正在运行项目的文件夹以及其他所需的值。
  1. 到#19行的位置进行设置并清除所有文件。
  2. 第20行确定是否存在可用于替换当前升级文件的升级文件。
    此逻辑与该概念无关。 这只是使用它的一种方式的示例。
  3. 第22行使用找到的文件中的版本号设置变量strVersion。
  4. 第23行查找当前文件名的最后一个点(。)。 IE浏览器 扩展名在哪里。
  5. 第24行到#25行设置了strBa,它是数据(%Ba)中使用的可替换参数之一。
  6. 第26行到第37行设置了strCmd的值,该值用于将所有可替换参数替换为SQL中的值。
  7. 第38行到#59行使用strCmd两次设置了SQL。 一次用于[Cmd1],另一次用于[Cmd2]。
  8. 第60行设置dbVar指向当前数据库。
  9. 第62行保存“ 自动压缩”属性的值。 如果过程失败并需要恢复,这一点很重要。
  10. 第62行至第63行使用strSQL中的SQL将实时数据添加到表中,但是仅在清除了之前可能遗留的所有数据之后。
    此数据将用于创建CMD文件。
  11. #64和#75行设置了intErr,以向ErrorHandler指示在进程崩溃时需要执行哪些操作来恢复。
  12. 第65行到第71行首先删除任何文件(如果存在),然后使用DoCmd.TransferText将新数据导出到该DoCmd.TransferText
    注意 该文件必须是.TXT文件,此文件才能起作用。
  13. 第72行到第73行首先清除实际CMD文件(如果存在),然后将.TXT文件重命名为.CMD。
  14. 第74行现在已导出并且不再需要删除表中的新数据。
  15. 第76行将“ 自动压缩”属性设置为off,以避免任何延迟关闭当前数据库。
  16. 从#76行到#83行提示操作员,并警告他们即将发生的事情。
  17. 第84行调用了我们刚刚创建的CMD文件。
    这将一直循环直到数据库成功关闭,然后它将复制和重命名文件,然后最终在Access中调用新数据库并删除自身(CMD文件)。
'UpgradeProject() prepares to upgrade from strN and returns true if all ok.
'  If all ok then calling code needs to close and quit the whole application
'  in order for the process to continue.
'12/09/2012 strBE used to ensure the upgraded FE uses the current BE or one
'           passed in the shortcut.
Public Function UpgradeProject() As Boolean
    Dim intX As Integer, intErr As Integer, intCompact As Integer
    Dim strNe As String, strVersion As String, strSQL As String
    Dim strMsg As String, strMode As String, strCmd As String
    Dim dbVar As DAO.Database 
    On Error GoTo Error_UpgradeProject
    strMode = SwitchMode(strType:="Process")
    Call SetStrings
    'Before we go any further, and regardless of whether or not an upgrade is
    '  even required, let's clear away any existing copy of UPGRADE.CMD.
    '  It's checked again immediately prior to being created.
    If Exist(strFo & "\UPGRADECMD.Txt") Then _
        Call KillFile(strFo & "\UPGRADECMD.Txt")
    strNe = GetUpgradeFile()
    If strNe = "" Then Exit Function
    strVersion = FormatVersion(strNe, "Display")
    intX = InStrRev(StringCheck:=strOr, StringMatch:=".")
    strBa = MultiReplace("%S_Last%F", "%S", Left(strOr, intX - 1), _
                                      "%F", Mid(strOr, intX))
    strCmd = "Replace(Nz([~C],''),'%Ac','%sAc')"
    strCmd = Replace("Replace(%C,'%Ba','%sBa')", "%C", strCmd)
    strCmd = Replace("Replace(%C,'%BE','%sBE')", "%C", strCmd)
    strCmd = Replace("Replace(%C,'%Fo','%sFo')", "%C", strCmd)
    strCmd = Replace("Replace(%C,'%Ne','%sNe')", "%C", strCmd)
    strCmd = Replace("Replace(%C,'%Or','%sOr')", "%C", strCmd)
    strCmd = MultiReplace(strCmd, "%sAc", strAc, _
                                  "%sBa", strBa, _
                                  "%sBE", "", _
                                  "%sFo", strFo, _
                                  "%sNe", strNe, _
                                  "%sOr", strOr)
    strSQL = "INSERT INTO [tblCMD]%L" _
           & "       ([Template]%L" _
           & "      , [Type]%L" _
           & "      , [Order]%L" _
           & "      , [Cmd1]%L" _
           & "      , [Cmd2])%L" _
           & "SELECT  [Template]%L" _
           & "      , [Type]%L" _
           & "      , [Order]%L" _
           & "      , [C1] AS [Cmd1]%L" _
           & "      , IIf([C2]='',Null,[C2]) AS [Cmd2]%L" _
           & "FROM    (SELECT False AS [Template]%L" _
           & "              , [Type]%L" _
           & "              , [Order]%L" _
           & "              , %C1 AS [C1]%L" _
           & "              , %C2 AS [C2]%L" _
           & "         FROM   [tblCMD]%L" _
           & "         WHERE  ([Template])%L" _
           & "           AND  ([Type]='U')) AS [qC]"
    strSQL = MultiReplace(strSQL, "%C1", Replace(strCmd, "~C", "Cmd1") _
                                , "%C2", Replace(strCmd, "~C", "Cmd2") _
                                , "%L", vbNewLine)
    Set dbVar = CurrentDb()
    intCompact = dbVar.Properties("Auto Compact")
    Call ClearTable(strTable:="tblCMD", strWhere:="(NOT [Template])")
    Call dbVar.Execute(Query:=strSQL, Options:=dbFailOnError)
    intErr = &H1
    If Exist(strFo & "\UPGRADECMD.Txt") Then _
        Call KillFile(strFo & "\UPGRADECMD.Txt")
    Call DoCmd.TransferText(TransferType:=acExportDelim, _
                            SpecificationName:="Upgrade Spec", _
                            TableName:="qryUpgrade", _
                            FileName:=strFo & "\UPGRADECMD.Txt", _
                            HasFieldNames:=False)
    If Exist(strFo & "\UPGRADE.CMD") Then Call KillFile(strFo & "\UPGRADE.CMD")
    Name strFo & "\UPGRADECMD.Txt" As strFo & "\UPGRADE.CMD"
    Call ClearTable(strTable:="tblCMD", strWhere:="(NOT [Template])")
    intErr = &H0
    dbVar.Properties("Auto Compact") = 0
    strMsg = MultiReplace("Upgrading from '%N'.%L%L" _
                        & "This process should be very quick (<1 minute).%L" _
                        , "%N", strNe _
                        , "%L", vbNewLine)
    Call MsgBox(Prompt:=strMsg, _
                Buttons:=vbInformation Or vbOKOnly, _
                TITLE:=CurrentProject.NAME)
    Call Shell(PathName:=strFo & "\UPGRADE.CMD", WindowStyle:=vbNormalFocus)
    Call SwitchMode(strType:=strMode)
    UpgradeProject = True
    Exit Function 
Error_UpgradeProject:
    If Not dbVar Is Nothing Then dbVar.Properties("Auto Compact") = intCompact
    If Exist(strFo & "\UPGRADE.CMD") Then Call KillFile(strFo & "\UPGRADE.CMD")
    If Exist(strFo & "\UPGRADECMD.Txt") Then _
        Call KillFile(strFo & "\UPGRADECMD.Txt")
    If (intErr And &H1) Then _
        Call ClearTable(strTable:="tblCMD", strWhere:="(NOT [Template])")
    strMsg = MultiReplace("Error (%N) :%L%D%L%L" & _
                          "Unable to complete upgrade process", _
                          "%N", Err, _
                          "%D", Err.DESCRIPTION, _
                          "%L", vbNewLine)
    Call MsgBox(Prompt:=strMsg, Buttons:=vbCritical Or vbOKOnly, TITLE:=strOr)
    Call SwitchMode(strType:=strMode)
End Function
'SetStrings() prepares the global string variables strA, strB, strF & strO.
Public Sub SetStrings()
    If strAc = "" Then
        With CurrentProject
            strAc = BareFolder(SysCmd(acSysCmdAccessDir)) & "\MSAccess.Exe"
            strOr = .NAME
            strFo = Left(.Path, 1)
            If strFo >= "A" And strFo <= "Z" And strFo <> Left(CurDir, 1) Then _
                Call ChDrive(Drive:=strFo)
            strFo = BareFolder(.Path)
            If BareFolder(CurDir) <> strFo Then Call ChDir(Path:=strFo)
        End With
    End If
End Sub
结论。

在Access中可以控制的内容几乎没有限制。 我包括一个

附件 ,可以提取到任何文件夹并运行。 附件使用外接程序工具栏提供对要测试的项目的访问。 首次运行时,它可能会立即升级您。 不用担心 升级版本完全相同,只是内部存储了更高的版本号。 使用加载项工具栏手动测试升级过程。

From: https://bytes.com/topic/access/insights/966089-control-external-processes-using-scripts-cmd

### 如何正确使用 `--os-cmd` 参数或其相关替代方案 在命令行工具中,参数的设计通常是为了提供灵活性和可扩展性。对于 `--os-cmd` 参数的具体实现方式以及其可能的相关替代方案,可以从以下几个方面进行分析: #### 1. **理解 `--os-cmd` 的功能** 如果某个命令支持 `--os-cmd` 参数,则该参数通常是用来执行操作系统级别的命令或者脚本[^3]。这种设计常见于需要集成外部操作的任务管理器、自动化工具或其他高级 CLI 工具。 例如,在某些场景下,可以通过指定此参数来运行特定的操作系统指令并将其结果嵌入到当前的工作流中。然而,具体的行为取决于工具本身的定义和支持范围。 --- #### 2. **通过命令行解析库实现自定义参数处理** 假设我们正在开发一个类似的工具,并希望支持类似于 `--os-cmd` 的功能,可以借助 JavaScript 的 `command-line-args` 库完成这一目标。以下是具体的代码示例: ```javascript const commandLineArgs = require('command-line-args'); // 定义参数结构 const optionDefinitions = [ { name: 'os-cmd', type: String, description: 'Execute an OS-level command' } ]; // 解析传入的命令行参数 const options = commandLineArgs(optionDefinitions); if (options['os-cmd']) { console.log(`Executing OS Command: ${options['os-cmd']}`); // 执行系统命令(需引入 child_process) const { exec } = require('child_process'); exec(options['os-cmd'], (error, stdout, stderr) => { if (error) { console.error(`Error executing command: ${stderr}`); return; } console.log(stdout); }); } else { console.log('No os-cmd parameter provided.'); } ``` 上述代码展示了如何利用 Node.js 和第三方模块解析命令行中的 `--os-cmd` 参数,并进一步调用系统的子进程接口执行对应的命令[^4]。 --- #### 3. **现有工具的支持情况** 并非所有的命令行工具都原生支持 `--os-cmd` 这样的参数名称。因此,当提到 S5CMD 或其他类似工具时,应查阅官方文档确认是否存在等效的功能。例如,S5CMD 主要用于对象存储交互,而它的核心功能并不涉及直接执行操作系统级命令。不过,它允许通过环境变量或配置文件间接影响行为[^1]。 假如确实需要一种跨平台的方式执行额外逻辑,可以选择编写简单的 Shell 脚本作为补充手段并与主要流程结合在一起。 --- #### 4. **安全性注意事项** 无论是在自己的项目里还是使用现成软件时,请务必注意潜在的安全隐患——尤其是动态拼接字符串以形成最终命令的情况下。这可能导致注入攻击等问题发生。推荐始终验证输入合法性后再继续后续动作[^5]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值