Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/powershell/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Powershell中修饰现有函数或传递函数对象?_Powershell_Functional Programming - Fatal编程技术网

如何在Powershell中修饰现有函数或传递函数对象?

如何在Powershell中修饰现有函数或传递函数对象?,powershell,functional-programming,Powershell,Functional Programming,假设我想将Powershell命令的输出保存到文件。我会像ls | out文件“path.txt”那样执行此操作。我每天做几次这样的调用,我担心函数调用(ls)会产生坏数据,破坏我的文件。我觉得我需要支援 对我来说,下一步是修饰out file调用,以便它自动将数据备份到单独的文件中。每天备份一次就足够了。这可以通过自定义out bak功能实现,如下所示。突然,我用ls | Out Bak“path.txt”实现了自动备份 这很好地解决了我的问题,但我希望能够对Out csv和类似的文件写入功能

假设我想将Powershell命令的输出保存到文件。我会像
ls | out文件“path.txt”
那样执行此操作。我每天做几次这样的调用,我担心函数调用(
ls
)会产生坏数据,破坏我的文件。我觉得我需要支援

对我来说,下一步是修饰
out file
调用,以便它自动将数据备份到单独的文件中。每天备份一次就足够了。这可以通过自定义
out bak
功能实现,如下所示。突然,我用
ls | Out Bak“path.txt”
实现了自动备份


这很好地解决了我的问题,但我希望能够对
Out csv
和类似的文件写入功能使用完全相同的模式。是否有方法将
Out File
命令作为参数传递给
Out Bak
,以便我可以将该函数用作输出命令的某种通用装饰器

让备份功能只执行其名称所建议的操作:备份文件

管道完成后,
backup
cmdlet将简单地复制文件。
要从以前的管道命令中找到文件路径,我们必须使用像AST parser这样的神秘东西:

function Backup {
    end {
        $bakCmdText = (Get-PSCallStack)[1].Position.text
        $bakCmd = [ScriptBlock]::Create($bakCmdText).
            Ast.EndBlock.Statements[0].PipelineElements[-2].CommandElements
        $bakParamInfo = if (!$bakCmd) { @{} }
            else { @{} + (Get-Command ($bakCmd[0].value)).Parameters }
        $bakSource = ''; $bakLiteral = $false; $bakPos = 0
        while (!$bakSource -and ++$bakPos -lt $bakCmd.count) {
            $bakToken = $bakCmd[$bakPos]
            if ($bakToken.ParameterName) {
                if ($bakToken.ParameterName -match '^(File|Literal)?Path$') {
                    $bakLiteral = $bakToken.ParameterName -eq 'LiteralPath'
                } elseif (!$bakParamInfo[$bakToken.ParameterName].SwitchParameter) {
                    $bakPos++
                }
                continue
            }
            $bakSource = if ($bakToken.StringConstantType -in 'SingleQuoted', 'BareWord') {
                $bakToken.value
            } else {
                [ScriptBlock]::Create($bakToken.extent.text).
                    InvokeWithContext(@{}, (Get-Variable bak* -scope 1))
            }
        }
        if (!$bakSource) {
            Write-Warning "Could not find file path in pipeline emitter: $bakCmdText"
            return
        }
        $backupTarget = "$bakSource" + '.' + [DateTime]::Now.ToShortDateString() + '.bak'
        $bakParams = @{ $(if ($bakLiteral) {'LiteralPath'} else {'Path'}) = "$bakSource" }
        copy @bakParams -destination $backupTarget -Force
    }
}

警告:它会以
$()
的方式失败,如
out文件“$($path)”| backup
,因为Get-PSCallStack出于某种原因返回表达式内容作为被调用方,而现在我不知道获取父调用上下文的其他方法。

@wOxxOm因为我希望备份函数使用与out命令相同的输出方法,这可能不起作用。。。备份功能如何知道管道中的下一步是什么?我不明白。由于备份方法不知道管道中的下一步,它无法知道是否使用正确的方法写入更新文件?当前我的
过程
-块有两个
输出文件
语句。我理解你的建议,因为我应该将后者(非备份语句)替换为直接传递到write语句。我担心的是,一条write语句将留在
进程
-块中,我希望该语句与另一条语句具有完全相同的类型。你明白我不明白的是什么吗?令人惊讶地复杂,但它很好地解决了我的确切问题!非常感谢。
 ls | Out-File $path | Backup
........ | Out-File foo.txt | Backup
........ | Out-File -FilePath "$path\$name" | Backup
........ | Export-Csv -NoTypeInformation bar.csv | Backup
function Backup {
    end {
        $bakCmdText = (Get-PSCallStack)[1].Position.text
        $bakCmd = [ScriptBlock]::Create($bakCmdText).
            Ast.EndBlock.Statements[0].PipelineElements[-2].CommandElements
        $bakParamInfo = if (!$bakCmd) { @{} }
            else { @{} + (Get-Command ($bakCmd[0].value)).Parameters }
        $bakSource = ''; $bakLiteral = $false; $bakPos = 0
        while (!$bakSource -and ++$bakPos -lt $bakCmd.count) {
            $bakToken = $bakCmd[$bakPos]
            if ($bakToken.ParameterName) {
                if ($bakToken.ParameterName -match '^(File|Literal)?Path$') {
                    $bakLiteral = $bakToken.ParameterName -eq 'LiteralPath'
                } elseif (!$bakParamInfo[$bakToken.ParameterName].SwitchParameter) {
                    $bakPos++
                }
                continue
            }
            $bakSource = if ($bakToken.StringConstantType -in 'SingleQuoted', 'BareWord') {
                $bakToken.value
            } else {
                [ScriptBlock]::Create($bakToken.extent.text).
                    InvokeWithContext(@{}, (Get-Variable bak* -scope 1))
            }
        }
        if (!$bakSource) {
            Write-Warning "Could not find file path in pipeline emitter: $bakCmdText"
            return
        }
        $backupTarget = "$bakSource" + '.' + [DateTime]::Now.ToShortDateString() + '.bak'
        $bakParams = @{ $(if ($bakLiteral) {'LiteralPath'} else {'Path'}) = "$bakSource" }
        copy @bakParams -destination $backupTarget -Force
    }
}