.ps1 脚本在 .bat 文件脚本中报告为“缺少结束符 '}'”

2024-01-04

我在将简短的 PowerShell 脚本转换为 cmd.exe .bat 文件脚本时遇到困难。错误消息(见下文)抱怨“缺少结束'}”。 .ps1 脚本按预期成功运行。

我在赋值语句末尾使用了分号字符。我用脱字符号 (^) 转义了垂直线(竖线)字符。我缺少什么?

这是 .bat 脚本和错误消息输出。

PS C:\src\t> Get-Content -Path .\DistributeFiles2.bat
powershell -NoLogo -NoProfile -Command ^
    "$ProjectPath = Join-Path -Path $Env:USERPROFILE -ChildPath 'Desktop\Project';" ^
    "$NFilesPerDirectory = 400;" ^
    "Get-ChildItem -File -Path (Join-Path -Path $Env:USERPROFILE -ChildPath 'Desktop\images') -Filter '*.jpeg' ^|" ^
        "ForEach-Object {" ^
            "# Check to see if the filename starts with four (4) digits.;" ^
            "if ($_.BaseName -match '^(\d{4}).*') {" ^
                "$FolderNumber = [math]::Floor([int]$Matches[1] / $NFilesPerDirectory);" ^
                "$FolderName = 'Folder' + $FolderNumber.ToString();" ^
                "$FolderPath = Join-Path -Path $ProjectPath -ChildPath $FolderName;" ^
                "# If the destination directory does not exist, create it.;" ^
                "if (-not (Test-Path -Path $FolderPath)) { mkdir $FolderPath -WhatIf ^| Out-Null }" ^
                "# Move the file to the destination directory.;" ^
                "Move-Item -Path $_.FullName -Destination $FolderPath -WhatIf" ^
            "}" ^
        "}"

回到 cmd.exe shell...

C:>DistributeFiles2.bat

 9:55:41.67  C:\src\t
C:>powershell -NoLogo -NoProfile -Command     "$ProjectPath = Join-Path -Path $Env:USERPROFILE -ChildPath 'Desktop\Project';"     "$NFilesPerDirectory = 400;"     "Get-ChildItem -File -Path (Join-Path -Path $Env:USERPROFILE -ChildPath 'Desktop\images') -Filter '*.jpeg' ^|"         "ForEach-Object {"             "# Check to see if the filename starts with four (4) digits.;"             "if ($_.BaseName -match '^(\d{4}).*') {"                 "$FolderNumber = [math]::Floor([int]$Matches[1] / $NFilesPerDirectory);"                 "$FolderName = 'Folder' + $FolderNumber.ToString();"                 "$FolderPath = Join-Path -Path $ProjectPath -ChildPath $FolderName;"                 "# If the destination directory does not exist, create it.;"                 "if (-not (Test-Path -Path $FolderPath)) { mkdir $FolderPath -WhatIf ^| Out-Null }"                 "# Move the file to the destination directory.;"                 "Move-Item -Path $_.FullName -Destination $FolderPath -WhatIf"             "}"         "}"
Missing closing '}' in statement block or type definition.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : MissingEndCurlyBrace

这是原始的 .ps1 脚本,它按预期工作。

PS C:\src\t> Get-Content -Path .\DistributeFiles.ps1
$ProjectPath = Join-Path -Path $Env:USERPROFILE -ChildPath 'Desktop\Project';
$NFilesPerDirectory = 400;
Get-ChildItem -File -Path (Join-Path -Path $Env:USERPROFILE -ChildPath 'Desktop\images') -Filter '*.jpeg' |
    ForEach-Object {
        # Check to see if the filename starts with four (4) digits.;
        if ($_.BaseName -match '^(\d{4}).*') {
            $FolderNumber = [math]::Floor([int]$Matches[1] / $NFilesPerDirectory);
            $FolderName = 'Folder' + $FolderNumber.ToString();
            $FolderPath = Join-Path -Path $ProjectPath -ChildPath $FolderName;
            # If the destination directory does not exist, create it.;
            if (-not (Test-Path -Path $FolderPath)) { mkdir $FolderPath -WhatIf | Out-Null }
            # Move the file to the destination directory.;
            Move-Item -Path $_.FullName -Destination $FolderPath -WhatIf
        }
    }
PS C:\src\t> .\DistributeFiles.ps1
What if: Performing the operation "Create Directory" on target "Destination: C:\Users\lit\Desktop\Project\Folder0".
What if: Performing the operation "Move File" on target "Item: C:\Users\lit\Desktop\images\0000.jpeg Destination: C:\Users\lit\Desktop\Project\Folder0".
What if: Performing the operation "Create Directory" on target "Destination: C:\Users\lit\Desktop\Project\Folder1".
What if: Performing the operation "Move File" on target "Item: C:\Users\lit\Desktop\images\0401.jpeg Destination: C:\Users\lit\Desktop\Project\Folder1".

从 .bat 文件脚本运行 .ps1 脚本也可以按预期工作。

PS C:\src\t> Get-Content -Path .\DistributeFiles.bat
@powershell -NoLogo -NoProfile -File "%~dp0%~n0.ps1"

PS C:\src\t> .\DistributeFiles.bat
What if: Performing the operation "Create Directory" on target "Destination: C:\Users\lit\Desktop\Project\Folder0".
What if: Performing the operation "Move File" on target "Item: C:\Users\lit\Desktop\images\0000.jpeg Destination: C:\Users\lit\Desktop\Project\Folder0".
What if: Performing the operation "Create Directory" on target "Destination: C:\Users\lit\Desktop\Project\Folder1".
What if: Performing the operation "Move File" on target "Item: C:\Users\lit\Desktop\images\0401.jpeg Destination: C:\Users\lit\Desktop\Project\Folder1".

Update:

根据@mklement0的建议,我删除了引号字符。两 (2) 个垂直线(竖线)字符被转义,并且行首插入符位于-match正则表达式被转义。我从一开始就避免在 .ps1 脚本中使用引号字符。仍然出现“缺少结束'}'”故障。我缺少什么?

C:>powershell -NoLogo -NoProfile -Command ^
More?     $ProjectPath = Join-Path -Path $Env:USERPROFILE -ChildPath 'Desktop\Project'; ^
More?     $NFilesPerDirectory = 400; ^
More?     Get-ChildItem -File -Path (Join-Path -Path $Env:USERPROFILE -ChildPath 'Desktop\images') -Filter '*.jpeg' ^| ^
More?         ForEach-Object { ^
More?             # Check to see if the filename starts with four (4) digits.; ^
More?             if ($_.BaseName -match '^^(\d{4}).*') { ^
More?                 $FolderNumber = [math]::Floor([int]$Matches[1] / $NFilesPerDirectory); ^
More?                 $FolderName = 'Folder' + $FolderNumber.ToString(); ^
More?                 $FolderPath = Join-Path -Path $ProjectPath -ChildPath $FolderName; ^
More?                 # If the destination directory does not exist, create it.; ^
More?                 if (-not (Test-Path -Path $FolderPath)) { mkdir $FolderPath -WhatIf ^| Out-Null }; ^
More?                 # Move the file to the destination directory.; ^
More?                 Move-Item -Path $_.FullName -Destination $FolderPath -WhatIf; ^
More?             }; ^
More?         };
Missing closing '}' in statement block or type definition.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : MissingEndCurlyBrace

更新2:

根据 @mklement0 一贯的好建议,这里是工作代码。

powershell -NoLogo -NoProfile -Command ^
    $ProjectPath = Join-Path -Path $Env:USERPROFILE -ChildPath 'Desktop\Project'; ^
    $NFilesPerDirectory = 400; ^
    Get-ChildItem -File -Path (Join-Path -Path $Env:USERPROFILE -ChildPath 'Desktop\images') -Filter '*.jpeg' ^| ^
        ForEach-Object { ^
            ^<# Check to see if the filename starts with four (4) digits.#^> ^
            if ($_.BaseName -match '^^(\d{4}).*') { ^
                $FolderNumber = [math]::Floor([int]$Matches[1] / $NFilesPerDirectory); ^
                $FolderName = 'Folder' + $FolderNumber.ToString(); ^
                $FolderPath = Join-Path -Path $ProjectPath -ChildPath $FolderName; ^
                ^<# If the destination directory does not exist, create it.#^> ^
                if (-not (Test-Path -Path $FolderPath)) { mkdir $FolderPath -WhatIf ^| Out-Null }; ^
                ^<# Move the file to the destination directory.#^> ^
                Move-Item -Path $_.FullName -Destination $FolderPath -WhatIf; ^
            }; ^
        };

  • In cmd.exe因此也在批处理文件中,^只充当转义字符unquoted strings;因此,一般来说你会not需要逃跑cmd.exe元字符,例如| inside "..."字符串为^|- 如果你这样做,^字符是retained.

  • However, it looks like using cmd.exe's line continuation (a line-ending ^) with double-quoted-per-line strings doesn't work robustly[1] (and having a single double-quoted string span multiple lines is fundamentally unsupported), so the solution is to use unquoted lines, on which you do need to escape | as ^|, among other characters.

下面是一个练习各种 PowerShell 语法结构的示例:

powershell -NoProfile -Command ^
  [Environment]::CommandLine; ^
  $ProjectPath = Join-Path -Path $Env:USERPROFILE -ChildPath 'Desktop\Project'; ^
  ^<# This is a comment - note the required *inline* comment syntax #^> ^
  $ProjectPath ^| ^
    ForEach-Object { \"[$ProjectPath]\" }; ^
  (42).ToString(); ^
  \"A & B\"

Note the inclusion of [Environment]::CommandLine; as the first statement, which will echo the command line as seen by PowerShell, which can help with troubleshooting. As an aside: When using PowerShell (Core) 7+'s CLI, pwsh.exe, rather than Windows PowerShell's powershell.exe, the command line reported is a reconstructed form that is not guaranteed to reflect the actual command line used; notably, "" sequences turn to \".

Note:

  • 每条内部线路必须有^ as the 最后特点在线上。

  • 因为续行不包括换行符,;必须用于显式终止每个 PowerShell 语句(最后一个除外)。

    • 注意:插入一个空行(没有结束它^) 语句之间确实not工作:虽然从技术上讲,它在传递给 PowerShell 时确实会产生实际的换行符,但由于缺乏整体双引号,PowerShell 将此类换行符视为与spaces,因此仍然需要;语句之间。

    • 正是由于这个原因,单行注释(# ...) are not支持此调用方法,因为这样的注释总是跨越该行的其余部分,不支持;结束它们 - 请参阅下一点。

  • 为了包括comments, 表格^<# ... #^>- 即(逃脱)inline必须使用注释- 正常的单行注释(# ....) are not支持(见上一点)。

  • cmd.exe的元字符需要单独的^- 逃避,即:

    • & | < > ^
    • Additionally, if called from a for /f statement:
      • = , ; ( )
  • "字符必须转义为\"以便电源外壳将它们视为要执行的命令的一部分(否则它们在命令行解析期间会被删除);所以,在可行的情况下,使用'...'(单引号)更容易.

    • 如果只有one or an 奇数 of "字符。在内部线上,将那个/最后一个转义为\^" (sic).

    • Inside \"...\", cmd.exe元字符做not need ^- 逃避,因为cmd.exe将这样的 PowerShell 转义字符串视为常规双引号字符串。

    • 但是,空白规范化适用于内部内容\"...\";也就是说,运行multiple空间被折叠成one每个空间;如果这是一个问题,请使用^"\"...\"^" (sic).

  • For 附加信息,包括一个for /f示例以及如何处理转义! when setlocal enabledelayedexpansion已生效,请参阅这个答案 https://stackoverflow.com/a/66085286/45375.


[1] It only works if you ensure that any interior "..."^ line and a closing "..." line starts with at least one whitespace character. However, in most cases it will be less effort and arguably more readable not to double-quote the individual lines and to instead selectively ^-escape cmd.exe's metacharacters, as shown.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

.ps1 脚本在 .bat 文件脚本中报告为“缺少结束符 '}'” 的相关文章

  • Powershell 工作流 DynamicActivity 编译器错误“。”预期使用 $Date 变量

    通常 powershell 错误会给我一些继续下去的机会 但是这个错误让我陷入了困境 要进行测试 请执行以下代码 workflow test date Date Get Date format yyyyMMddHHmm Verbose Wr
  • Powershell:获取 FQDN 主机名

    我想通过 powershell 脚本检索 Windows 服务器的 FQDN 名称 到目前为止我已经找到了2个解决方案 server Invoke Command ScriptBlock hostname 上面的行将仅打印服务器的短名称 s
  • PowerShell从csv中提取特定列并将其存储在变量中

    我的keys csv文件看起来像这样 PrjKey BldKey key LS LOOKUPSNAP1 LS LOOKUPSNAP1 LS LSUH3 LS LSUH3 LSPERF LPMDS0 LSPERF LPMDS0 LSPERF
  • 如何在 C# 中获取 CMD/控制台编码

    我需要指定正确的代码页来使用 zip 库打包文件 正如我所见 我需要指定控制台编码 在我的例子中为 866 C Users User gt mode Status for device CON Lines 300 Columns 130 K
  • PowerShell Get-VHD“不是现有的虚拟硬盘文件”

    在 Hyper V 中创建新 VM 时 为了使事情井井有条 我在创建关联的 VHDX 文件时使用特定的命名约定 命名约定是 VM FQDN 后跟 SCSI 控制器连接点 后跟 VM 内部的驱动器名称或使用名称 我将 SCSI 和 Name
  • Powershell强类型环境变量

    我想设置一个强类型环境变量 当我使用 env 时它似乎 丢失 了它的类型 在原始函数中它工作正常 function Create ThisCrap Microsoft ApplicationInsights TelemetryClient
  • Powershell,从txt文件读取并格式化数据(删除行,删除之间的空格)

    我对 powershell 真的很陌生 我想使用powershell读取txt文件并将其更改为其他格式 从 txt 文件中读取 设置数据格式 删除行 删除之间的空格 记录计数 T 000000002 9 个字符 然后将输出写入新文件 我两天
  • 在 cygwin 和 powershell 中查看不同的 gem 列表

    我用的是gem listpowershell 和 cygwin 中的命令都显示不同的 gem 列表 Cygwin 显示 LOCAL GEMS bundler 1 2 3 json 1 7 5 minitest 2 12 1 rake 0 9
  • Invoke-WebRequest SSL 失败?

    当我尝试使用时Invoke WebRequest我收到一些奇怪的错误 Invoke WebRequest Uri https idp safenames com Invoke WebRequest The underlying connec
  • 如何使用 PowerShell 捕获全局击键?

    Powershell 可以监听并捕获按键吗 是否可以编写一个 PowerShell 脚本 例如自动热键 https www autohotkey com 位于托盘中并等待您按下预定义的键盘键才开始执行 并且每次按下所述键时可能不会返回而是触
  • 如何编写从管道输入读取的 powershell 函数?

    SOLVED 以下是使用管道输入的函数 脚本的最简单示例 每个的行为都与通过管道传输到 echo cmdlet 相同 作为函数 Function Echo Pipe Begin Executes once before first item
  • 在Windows cmd中获取精确到毫秒的系统时间

    我试图在 Windows cmd 中将系统时间精确 到毫秒 我知道可以使用以下方法获得厘秒精度 echo time 我发现其他问题提出了完全相同的问题 但没有答案可以完全回答该问题 这是我到目前为止发现的 该解决方案仅适用于厘秒精度 与我上
  • 使用 PowerShell 修改 Visual Studio 解决方案和项目文件

    我们目前正在重新组织源代码 将内容移动到新目录中 结构 这会影响我们的 Visual Studio 解决方案和项目文件 其中诸如程序集引用 可能的输出目录 构建前和构建后事件等 必须更新以反映我们的更改 由于我们有许多解决方案和项目 我希望
  • 防止集成终端自动打开

    每当我在 VS Code 中打开 PowerShell 脚本时 集成终端就会打开 如何防止集成终端自动打开 我搜索了 终端 的设置 但没有发现与自动启动相关的内容 VSCode 会记住您的上一次会话 因此 如果关闭终端并退出 VSCode
  • 拖放到 Powershell 脚本

    我以为我已经找到了这个问题的答案 但我玩得越多 我就越发现它是 Powershell 的设计缺陷 我想拖放 或使用发送到机制 将多个文件和 或文件夹作为数组传递到 Powershell 脚本 测试脚本 Test ps1 param stri
  • “Microsoft.AspNet.Server.Kestrel”不包含适合入口点的静态“Main”方法

    我正在尝试运行最新的Asp Net 5 个示例 https github com aspnet Home 当前为 1 0 0 rc1 update1 来自 Windows 10 上的 powershell 我将活动和默认 DNX 设置为 C
  • 为管道重用自定义对象时出现意外结果

    A while ago I changed my Join Object https stackoverflow com a 45483110 1701026 cmdlet which appeared to cause a bug whi
  • 在 C# 中检查 PowerShell 执行策略的最佳方法是什么?

    当你跑步时Get ExecutionPolicy在 PowerShell 中 它得到有效的执行政策 https learn microsoft com en us powershell module microsoft powershell
  • 从 Powershell 更新计划任务脚本

    我正在尝试编写一个每天运行一次的 Powershell 脚本 它将执行的众多功能之一是确保脚本本身是最新的 我的问题是 由于我对脚本进行了版本控制 因此我需要更新从脚本中创建的计划任务 我在这里考虑了两种不同的方法 其中我也无法弄清楚 我最
  • 从某个文件夹启动随机批处理文件

    问题是这样的 我有一个名为 abc 的文件夹 其中包含几个批处理文件 它们的命名如下 abc1 batabc2 batabc3 batabc4 bat 等等 我需要一个脚本 当我单击它时 它会随机启动其中一个批处理文件 我需要的脚本将存储在

随机推荐