使用PowerShell和 wkhtmltopdf生成PDF

前端开发 2026-07-12

我知道还有其他方法可以做这件事,但我真的在努力让自己在PowerShell方面变得更好,我怎么也搞不明白为什么这行不通。

我有一个HTML文件的目录,我用PowerShell遍历它们,把它们发送给wkhtmltopdf,并尝试把输出放到另一个目录作为PDF。下面是我尝试使用的命令:

get-childitem -r -attributes !directory -path test_input | % {$_.fullname} | foreach-object { & "wkhtmltopdf.exe" -O landscape --enable-local-file-access $_ "test_output\\$_.pdf" }

我怀疑问题出在 \$_.pdf这一部分,因为我已经把这一部分改来改去好几次了,如果我改成下面这样,而不是上面的:

get-childitem -r -attributes !directory -path test_input | % {$_.fullname} | foreach-object { & "wkhtmltopdf.exe" -O landscape --enable-local-file-access $_ "test_output\\$($_.length).pdf" }

它可以工作,但PDF的名称会是原始文件完整路径的长度,也就是像 "90.pdf" 这样的名字。

如果不再使用长度,而改用namestring:

get-childitem -r -attributes !directory -path test_input | % {$_.fullname} | foreach-object { & "wkhtmltopdf.exe" -O landscape --enable-local-file-access $_ "test_output\\$($_.namestring).pdf" }

PDF的名字将只有 ".pdf"——在那种情况下似乎完全忽略了变量。我尝试了很多不同的属性在 $_ 对象上,但只有length这个属性替换了值,所以我完全不知道出了什么问题。

解决方案

tl;dr

在你自己的回答的基础上:

Get-ChildItem -Recurse -File -LiteralPath test_input | 
  ForEach-Object { 
    & "wkhtmltopdf.exe" -O landscape --enable-local-file-access $_.FullName "test_output\$($_.BaseName).pdf" 
  }

注:

  • 为了概念上的清晰,上述使用 [ForEach-Object] 的完整名称来代替 %,它是其中一个内置别名。

  • 只有你把目标可执行文件放在引号中,语法上才需要通过 & 调用它,即 调用运算符;如果不加引号(且没有变量引用),& 就是可选的——请参阅 这个回答 了解更多。
    换句话说: & "wkhtmltopdf.exe" 可以仅用 wkhtmltopdf.exe 来替换。

  • -attributes !directory 已被替换为 -File,以请求只输出 文件,这更简洁、概念上也更直接。

  • 由于输入路径,test_input,不包含通配符字符,我假设它应该被逐字(逐字面)处理,在这种情况下,稳妥的做法是使用 -LiteralPath 而不是 -Path,因为恰好包含 [ / ] 的字面输入路径可能会被误解;请参阅 [这个答案] 获取更多信息。


详细解释:

我怀疑问题出在 \\$_.pdf 这一部分

确实:

  • 顺便提一下,使用 \\ 代替 \ 是不必要的,但也无害:在PowerShell本身中,\ 没有任何特殊含义,因此不需要转义——请参阅 [这个回答] 的底部部分了解更多信息。
    然而,将字面量的 \\ 作为路径分隔符通常也会被安静地容忍。

  • 关键是,由于前面的 % { $_.fullname } 管道段,$_ 包含当前处理的输入文件的完整路径,而你的意图是让 $_ 指向基名,即输入文件没有扩展名的文件名。

我已经尝试了 $_ 对象的很多不同属性,只有 length 替换了值,我也不清楚到底是怎么回事。

  • % { $_.fullname }% 是内置别名之一,指向内置 [ForEach-Object])输出每个输入文件的完整路径,作为一个字符串,例如一个 [[string]] 的实例,其唯一个(.NET类型原生)属性是 .Length

  • 在PowerShell中,默认情况下,任何尝试引用一个 不存在 的属性,都会安静地返回 $null

  • 在字符串插值的上下文中,即在一个可展开的(插值)字符串(双引号,即 "...")中$null 简单地变成空字符串,即不会向结果字符串添加任何字符,这解释了你试图使用一个(设想的).namestring 属性的结果。

  • 通过 Set-StrictMode -Version 2 或以上,你可以指示PowerShell对尝试访问不存在的属性时报告错误,但这有陷阱——请参阅 this answer

因此:

  • Do not use % { $_.fullname }, as it prevents you from (easily) deriving the base file name from each input file in subsequent pipeline segments.
  • Using the input file objects emitted by Get-ChildItem - which are of type System.IO.FileInfo - as-is, allows you to conveniently reference the base file name as $_.BaseName

  • Inside "..." - as shown in your own answer - referencing $_.BaseName requires enclosure in $(...), for syntactic reasons explained in this answer.

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章