Powershell“调用”将重定向传递给程序,而不是执行操作

Powershell 'call' passing redirects to program instead of actioning it

提问人:jc508 提问时间:4/17/2023 更新时间:9/27/2023 访问量:54

问:

我正在尝试让 powershell 调用具有构造参数列表的 exe - 并将响应通过管道传递到日志文件。 我的问题是重定向字符似乎被传递给了 exe。 (我也花了将近一天的时间在充满空格的路径名称周围找到正确的引号!!)

exe 的语法是

   filemeta  {-d|-i|-e} [-c] [-f=<directory name>] [-x=<file name>] [-v]
             [-p] [--] [--version] [-h] <file name> ...

正如你所看到的,重复。我认为重定向作为另一个文件名传递的原因首先是错误消息 找不到文件“>>” 其次,日志文件未填充

粘贴到命令提示符中的以下命令将执行预期的操作。它只是如何将其包装在 powershell 文件迭代中

"C:\Program Files\File Metadata\FileMeta.exe" -i -f="M:\metadata_XML_tobe\ManagedCatalog\Business Records\Morse Bakery"  "M:\ManagedCatalog\Business Records\Morse Bakery\Morse Bakery Book 1-000.JPG"  >>"M:\metadata_XML_tobe\apply_doc_id_20230412-124532.log" 2>>&1 

到目前为止,PowerShell 命令是......

$metaDataPath = 'M:\metadata_XML_tobe'
$timeStr = get-date -Format 'yyyyMMdd-HHmmss' 
$logFileName = $metaDataPath + "\apply_doc_id_" + $timeStr + ".log"
$files = Get-ChildItem -Path $metaDataPath -Recurse -Include *.xml
$quote = '"'
$hits  = 0
foreach ($f in $files){
    $hits++
    if ($hits -ge 5) {
        break
    }
    $directory = [System.IO.Path]::GetDirectoryName($f)
    $realFile_name = $f.FullName.Replace('.metadata.xml', '')
    $realFile_name = $realFile_name.Replace('\metadata_XML_tobe', '' )
    $parm1 = '-i'  
    $parm2 = '-f='+ $quote + $directory + $quote 
    $parm3 = $quote + $realFile_name + $quote
    $parm4 = ' >>'  
    $parm5 = $quote + $logFileName + $quote
    $parm6 = ' 2>>&1'  
    Write-Host '**************'
    Write-Host $f.FullName 
    Write-Host  '   Parm1   = ' $parm1
    Write-Host  '   Parm2   = ' $parm2
    Write-Host  '   Parm3   = ' $parm3
    Write-Host  '   Parm4   = ' $parm4
    Write-Host  '   Parm5   = ' $parm5
    Write-Host  '   Parm6   = ' $parm6
    echoargs 'C:\Program Files\File Metadata\FileMeta.exe' $parm1 $parm2 $parm3 $parm4 $parm5 $parm6
    # & 'C:\Program Files\File Metadata\FileMeta.exe' $parm1 $parm2 $parm3 $parm4 $parm5 $parm6
}

这给出了-----的输出

M:\metadata_XML_tobe\ManagedCatalog\Church Records\Catholic Church Euroa\Baptism Records\1904-1948\Baptism Records 1904-1948-003.JPG.metadata.xml
   Parm1   =  -i
   Parm2   =  -f="M:\metadata_XML_tobe\ManagedCatalog\Church Records\Catholic Church Euroa\Baptism Records\1904-1948"
   Parm3   =  "M:\ManagedCatalog\Church Records\Catholic Church Euroa\Baptism Records\1904-1948\Baptism Records 1904-1948-003.JPG"
   Parm4   =   >>
   Parm5   =  "M:\metadata_XML_tobe\apply_doc_id_20230417-105352.log"
   Parm6   =   2>>&1
Arg 0 is <C:\Program Files\File Metadata\FileMeta.exe>
Arg 1 is <-i>
Arg 2 is <-f=M:\metadata_XML_tobe\ManagedCatalog\Church Records\Catholic Church Euroa\Baptism Records\1904-1948>
Arg 3 is <M:\ManagedCatalog\Church Records\Catholic Church Euroa\Baptism Records\1904-1948\Baptism Records 1904-1948-003.JPG>
Arg 4 is < >>>
Arg 5 is <M:\metadata_XML_tobe\apply_doc_id_20230417-105352.log>
Arg 6 is < 2>>&1>

或者如果 echoargs 被换掉

**************
M:\metadata_XML_tobe\ManagedCatalog\Church Records\Catholic Church Euroa\Baptism Records\1904-1948\Baptism Records 1904-1948-003.JPG.metadata.xml
   Parm1   =  -i
   Parm2   =  -f="M:\metadata_XML_tobe\ManagedCatalog\Church Records\Catholic Church Euroa\Baptism Records\1904-1948"
   Parm3   =  "M:\ManagedCatalog\Church Records\Catholic Church Euroa\Baptism Records\1904-1948\Baptism Records 1904-1948-003.JPG"
   Parm4   =   >>
   Parm5   =  "M:\metadata_XML_tobe\apply_doc_id_20230417-105958.log"
   Parm6   =   2>>&1
Imported metadata to M:\ManagedCatalog\Church Records\Catholic Church Euroa\Baptism Records\1904-1948\Baptism Records 1904-1948-003.JPG from M:\metadata_XML_tobe\ManagedCatalog\Church Records\Catholic Church Euroa\Baptism Records\1904-1948\Baptism Records 1904-1948-003.JPG.metadata.xml
Cannot find file " >>"

请帮我了解这个迷宫

JC公司

PowerShell 引用 IO 重定向

评论


答:

0赞 mklement0 4/17/2023 #1

与任何 shell 一样,诸如此类的元字符不是按字面意思使用的,未加引号元字符不会被视为:>

# OK: > $null redirects the success-stream output to $null, i.e. 
#     *discards* it:
# NO OUTPUT, as expected.
Write-Output hi > $null

与。

# !! Due to saving *string* value '> $null' in a variable
# !! and passing that variable, its *verbatim value* is passed.
# OUTPUTS 'hi' and '> $null'
$var = '> $null'
Write-Output hi $var

也就是说,使用变量为给定的目标可执行文件指定单个传递参数与尝试传递整个重定向表达式(例如通过变量)有根本的不同。>> file

换言之:不能使用变量传递命令行中具有语法功能的元素,例如 或 。>|

为了使 PowerShell 能够识别重定向运算符>>>),必须按字面意思指定它,不带引号,你可以自由地将重定向目标文件(或$null抑制输出)作为变量传递;例如:

# Define the redirection target (output file) as a variable.
$file = 'temp file.txt'

# Now pass the variable to the - unquoted - > operator.
Write-Output hi > $file

但是,如果重定向目标是另一个流的编号(例如,为了将错误 () 合并到成功流 () 中),则无法通过变量指定该编号。2>&121

$streamNumber = 1

# !! Does NOT work and triggers a *syntax error*:
# !! -> "Missing file specification after redirection operator."
Write-Output hi 2>&$streamNumber

但请注意,PowerShell 仅支持(即成功输出流)作为重定向目标。1

请继续阅读解决方案,以防您确实需要通过包含重定向运算符作为其值一部分的变量来指定整个重定向表达式


如果确实需要通过变量指定任意重定向表达式,则可以使用 Invoke-Expression(但是,通常要避免这种情况):

# Define the command to invoke with all its arguments, but without redirections,
# as a script block ({ ... }), to be invoked later.
# The block may contain *multiple* statements.
$scriptBlock = { Write-Output hi }

# Define the desired redirection expression as a variable.
$redirection = '> $null'

# This is now the equivalent of:
#   & { Write-Output hi } > $null
# or, given that there's just *one* command in the script block:
#   Write-Output hi > $null
# Note the need to escape the $ in $scriptBlock as `$, 
# so as to prevent *up-front* expansion of the variable reference.
Invoke-Expression "& `$scriptBlock $redirection"