【问题标题】:Running List of CMD lines from Excel从 Excel 运行 CMD 行列表
【发布时间】:2018-04-21 05:33:03
【问题描述】:

任何人都可以帮助满足以下要求吗?

要求 A:

我想创建一个循环来在 CMD 中运行命令字符串列表,只要 C 列中有一个非零值。我想我需要为我的起始行定义一个变量 i,因为这将始终相同,然后运行 ​​Shell(),从行 i,列 F 的相应单元格中提取命令字符串。当 Cells(i, "C") 不是空白时,继续,将 i 增加 1。

要求 B:

我还想将此宏链接到一个目录中,该目录由一个较早的宏存放在单元格中,该宏列出了所选目录中的所有文件。

这就是我所拥有的,没有任何循环..

Sub Run_Renaming()

    Dim CommandString As Long
    Dim i As Integer
    i = 5

    'Other steps:
        '1 - need to pick up variable (directory of files listed, taken from first macro
        'when doing manually, I opened command, went to correct directory, then pasted
        'the commands. I'm trying to handle pasting the commands. I'm not sure if I need
        'something to open CMD from VBA, then run through the below loop, or add opening
        'CMD and going to the directory in each iteration of the below loop...

        '2 - Need to say - Loop below text if Worksheets("Batch Rename of Files").Cells(i, "C").Value is no blank

         CommandString = Worksheets("Batch Rename of Files").Cells(i, "F").Value
         Call Shell("cmd.exe /S /K" & CommandString, vbNormalFocus)

    'Other steps:
        '3 - need to increase i by 1

        '4 - need to check if C column is blank or not

        '5 - need to end of C column is blank

End Sub

背景:

我正在为朋友创建一个文件重命名工具。他们可以使用 excel,但不能使用编程语言或命令提示符。因此,我不想有任何步骤,例如创建建议的批处理文件here,这会使我的朋友的事情变得复杂。

我创建了一个 excel 文件:

Tab 1 - 用于创建新文件名列表的模板表。通过连接多个单元格、添加文件类型并输出到一系列单元格来工作。为 CMD 创建重命名命令字符串时,Tab 两个指向此范围的链接

Tab 2 -

Button 1 - 下面是Sub rename()。 VBA在C列中列出选定目录中的文件

列 F 创建一个命令行,该命令行将根据 Tab 1 的输入将文件 A 重命名为文件 B,即 ren "File 1" "A1_B1_C1.xlsx"

Button 2 - 指的是一个重命名宏(上面的要求 1 和 2),它从按钮 1 中选取选定的目录,并在该目录中运行所有重命名命令字符串

Sub rename()

    Dim xRow As Long
    Dim xDirect$, xFname$, InitialFoldr$

    InitialFoldr$ = "C:\"

    Worksheets("Batch Rename of Files").Activate
    Worksheets("Batch Rename of Files").Range("C4").Activate

    With Application.FileDialog(msoFileDialogFolderPicker)

        .InitialFileName = Application.DefaultFilePath & "\"
        .Title = "Please select a folder to list Files from"
        .InitialFileName = InitialFoldr$
        .Show

        If .SelectedItems.Count <> 0 Then

            xDirect$ = .SelectedItems(1) & "\"
            xFname$ = Dir(xDirect$, 7)

            Do While xFname$ <> ""
                ActiveCell.Offset(xRow) = xFname$
                xRow = xRow + 1
                xFname$ = Dir
            Loop

        End If

    End With

End Sub

【问题讨论】:

  • 看起来像是最后的第三个要求,即额外的按钮。您的要求 B 听起来您可能正在尝试选择一个文件夹路径并将其与 CMD 连接,然后再将其传递给 shell 命令?认为您需要一个变量来保存输入框的结果(收集用户在文件夹子例程中循环的文件中选择的文件夹),该变量被接受为重命名过程的参数。另外,当您在 shell 脚本中指定 Command 时,您的意思是 CMD 吗?如果是这样,请使用一致的名称并使其具体且不含歧义,例如命令文本。
  • startRow 是常量,即始终相同吗?还需要至少查看列出目录中文件的子签名。 F 列文本的示例以及某些数据的图像会有所帮助。以及由按钮调用调用的子代码,它允许用户选择一个文件夹。
  • 感谢 cmets QHarr,我已尽力更新。

标签: vba loops cmd renaming


【解决方案1】:

注意事项:

1) 我不完全清楚您的数据等是如何布置的,因此我提供了一种实现您的目标的方法,其中涉及我清楚的元素。

2) 老实说,就个人而言,我会尽可能多地使用数组或字典,而不是在工作表中前后移动。

不过……

按照您的要求大纲和一点粗略和准备,我们有:

1) 使用您的宏 rename(重命名为 ListFiles 并进行一些小调整)将所选文件夹名称写入 Worksheets("Batch Rename of Files") 中的 Range("A1") 并将文件名写入 C 列。

2) 使用第二个宏RenameFilesWorksheets("Batch Rename of Files") 的 F 列获取重命名 shell 命令;将这些写到桌面上的批处理文件中;添加一个额外的第一行命令,将工作目录设置为Range("A1") 中给出的所选文件夹(要求 A)。 shell命令执行.bat文件,完成重命名(需求B)然后有一行删除.bat文件。

我猜这是实现目标的一种更有效的方法,而不是循环 F 列范围一次执行一个命令。

我没有尝试以任何进一步的方式优化代码(我添加了一些现有的类型化函数。)还有许多其他可以改进的地方,但这是为了帮助您实现您的要求。

告诉我进展如何!

Tab1 布局(包含新文件名的工作表)

文件布局的批量重命名(包含第一个宏和按钮输出的工作表)

工作表布局文件批量重命名

在一个名为ListFiles的标准模块中:

Option Explicit

Public Sub ListFilesInDirectory()

    Dim xRow As Long
    Dim xDirect$, xFname$, InitialFoldr$ 'type hints not really needed
    Dim wb As Workbook
    Dim wsTab2 As Worksheet

    Set wb = ThisWorkbook
    Set wsTab2 = wb.Worksheets("Batch Rename of Files")

    InitialFoldr$ = "C:\"

    Dim lastRow As Long
    lastRow = wsTab2.Cells(wsTab2.Rows.Count, "C").End(xlUp).Row

    wsTab2.Range("C4:C" & lastRow).ClearContents 'Get rid of any existing file names

    wsTab2.Range("C4").Activate

    With Application.FileDialog(msoFileDialogFolderPicker)

        .InitialFileName = Application.DefaultFilePath & "\"
        .Title = "Please select a folder to list Files from"
        .InitialFileName = InitialFoldr$
        .Show

        If .SelectedItems.Count <> 0 Then

            xDirect$ = .SelectedItems(1) & "\"
            xFname$ = Dir(xDirect$, 7)
            wsTab2.Range("A1") = xDirect$

            Do While xFname$ <> vbNullString
                ActiveCell.Offset(xRow) = xFname$
                xRow = xRow + 1
                xFname$ = Dir
            Loop

        End If

    End With

End Sub

在一个名为FileRenaming的标准模块中:

Option Explicit

Sub RenameFiles()

    Dim fso As New FileSystemObject
    Dim stream As TextStream
    Dim strFile As String
    Dim strPath As String
    Dim strData As Range
    Dim wb As Workbook
    Dim wsTab2 As Worksheet
    Dim currRow As Range

    Set wb = ThisWorkbook
    Set wsTab2 = wb.Worksheets("Batch Rename of Files")

    strPath = wsTab2.Range("A1").Value2

    If strPath = vbNullString Then

        MsgBox "Please ensure that Worksheet Batch Rename of Files has a directory path in cell A1"

    Else

        If Right$(Trim$(strPath), 1) <> "\" Then strPath = strPath & "\"

        strFile = "Rename.bat"

        Dim testString As String
        Dim deskTopPath As String
        deskTopPath = Environ$("USERPROFILE") & "\Desktop" 'get desktop path as this is where .bat file will temporarily be saved

        testString = fso.BuildPath(deskTopPath, strFile) 'Check if .bat already exists and delete

        If Len(Dir(testString)) <> 0 Then 
            SetAttr testString, vbNormal
            Kill testString
        End If

        Set stream = fso.CreateTextFile(deskTopPath & "\" & strFile, True) 'create the .bat file

        Dim lastRow As Long
        lastRow = wsTab2.Cells(wsTab2.Rows.Count, "C").End(xlUp).Row

        Set strData = wsTab2.Range("F4:F" & lastRow) 'Only execute for as many new file names as present in Col C (in place of your until blank requirement)

        stream.Write "CD /D " & strPath & vbCrLf

        For Each currRow In strData.Rows 'populate the .dat file
            stream.Write currRow.Value & vbCrLf
        Next currRow

        stream.Close

        Call Shell(testString, vbNormalFocus)

        Application.Wait (Now + TimeValue("0:00:01"))  'As sometime re-naming doesn't seem to happen without a pause before removing .bat file

        Kill testString

        MsgBox ("Renaming Complete")
    End If
End Sub

工作表中的按钮代码批量重命名文件

Private Sub CommandButton1_Click()

    ListFilesInDirectory

End Sub

Private Sub CommandButton2_Click()
    RenameFiles
End Sub

.bat 文件内容示例

第 2 版

这是一个不同的版本,它使用字典并将参数从一个子传递到另一个。因此,这将是一个仅与一个按钮按下操作相关联的宏,即不会有第二个按钮。单个按钮将调用ListFiles,后者又调用第二个宏。可能需要您进入工具 > 参考并添加 Microsoft Scripting Runtime 参考。

假设您在选项卡 1 的 Col D 中具有与文件夹中找到的文件数量相匹配的新文件名数量(根据您的脚本来获取文件夹中的文件)。我已删除过时的类型引用。请向 RubberDuck VBA 加载项工作人员大喊,让加载项拾取这些内容。

在一个标准模块中:

Option Explicit

Public Sub ListFiles()

    Dim xDirect As String, xFname As String, InitialFoldr As String
    Dim wb As Workbook
    Dim ws As Worksheet
    Dim dict As New Scripting.Dictionary
    Dim counter As Long

    Set wb = ThisWorkbook
    Set ws = wb.Worksheets("Tab1") 'Worksheet where new file names are

    counter = 4 'row where new file names start

    InitialFoldr = "C:\"

    With Application.FileDialog(msoFileDialogFolderPicker)

        .InitialFileName = Application.DefaultFilePath & "\"
        .Title = "Please select a folder to list Files from"
        .InitialFileName = InitialFoldr
        .Show

        If .SelectedItems.Count <> 0 Then

            xDirect = .SelectedItems(1) & "\"
            xFname = Dir(xDirect, 7)

            Do While xFname <> vbNullString

              If Not dict.Exists(xFname) Then
                  dict.Add xFname, ws.Cells(counter, "D")  'Or which ever column holds new file names. This add to the dictionary the current name and new name
                  counter = counter + 1
                  xFname = Dir
              End If
            Loop

        End If

    End With

    RenameFiles xDirect, dict 'pass directory path and dictionary to renaming sub

End Sub

在另一个标准模块中

Public Sub RenameFiles(ByVal folderpath As String, ByRef dict As Dictionary)

    Dim fso As New FileSystemObject
    Dim stream As TextStream
    Dim strFile As String
    Dim testString As String
    Dim deskTopPath As String

    strFile = "Rename.bat"
    deskTopPath = Environ$("USERPROFILE") & "\Desktop"
    testString = fso.BuildPath(deskTopPath, strFile)

    'See if .dat file of same name already on desktop and delete (you could overwrite!)
    If Len(Dir(testString)) <> 0 Then
        SetAttr testString, vbNormal
        Kill testString
    End If

    Set stream = fso.CreateTextFile(testString, True)

    stream.Write "CD /D " & folderpath & vbCrLf

    Dim key As Variant

    For Each key In dict.Keys
        stream.Write "Rename " & folderpath & key & " " & dict(key) & vbCrLf 'write out the command instructions to the .dat file
    Next key

    stream.Close

    Call Shell(testString, vbNormalFocus)

    Application.Wait (Now + TimeValue("0:00:01"))  'As sometime re-naming doesn't seem to happen without a pause before removing .bat file

    Kill testString

   ' MsgBox ("Renaming Complete")

End Sub

脚本运行时参考:

添加运行时引用

查找桌面路径的其他方法。取自Allen Wyatt

在标准模块中添加以下内容:

Public Function GetDesktop() As String
    Dim oWSHShell As Object

    Set oWSHShell = CreateObject("WScript.Shell")
    GetDesktop = oWSHShell.SpecialFolders("Desktop")
    Set oWSHShell = Nothing
End Function

然后在其余代码中替换 deskTopPath =..... 的任何实例,例如:

deskTopPath = Environ$("USERPROFILE") & "\Desktop"

desktopPath = GetDesktop

【讨论】:

  • 感谢 QHarr 提供的选项,我会仔细查看以更好地理解这一切。我已经用批处理文件尝试了上面的代码。宏 1 有效,但宏 2 无法定义: Sub RenameFiles() Dim fso As New FileSystemObject 您可以在此处访问更新版本drive.google.com/file/d/144zqlxZKUI4Ze1luZl2aH7yhFUjmJpKM/…
  • 你是否添加了对微软脚本运行时的引用?
  • 我还在代码中添加了一些解释。并在此处查看添加运行时参考库stackoverflow.com/questions/3233203/…
  • 谢谢 - 现在就到这里: Set stream = fso.CreateTextFile(deskTopPath & "\" & strFile, True) 但会引发错误。我替换为 Set stream = fso.CreateTextFile("D:\Users\JAMOSULL\Desktop" & "\" & strFile, True) 并且这有效 - 我猜这是驱动器号问题?但是,我在这里得到一个错误:Call Shell(testString, vbNormalFocus)
  • 只需将下面的 desktopPath = Environ$("USERPROFILE") & "\Desktop" 更改为 desktopPath = "D:\Users\JAMOSULL\Desktop" 并将另一行恢复为 Set stream = fso .CreateTextFile(deskTopPath & "\" & strFile, True)
猜你喜欢
  • 2021-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多