powershell - 如何编写包装 sed/perl/etc 命令的 powershell 函数

标签 powershell

我有许多我经常使用的 sed/perl/etc “单行”命令:

  • head -1 (打印文件的第一行)
  • sed $d (删除文件的最后一行)
  • perl -pe '$_ = qq($. $_)' (文件中的行数)

  • 你明白了。

    所有这些命令都有相同的行为——它们可以从标准输入中获取输入,或者处理一系列名称作为参数传递的文件。我想将这些常用脚本包装为 Powershell 函数,这样我就不必记住要使用的确切语法。但是,别名不是那样工作的,如果我用函数做“明显”的方法:
    function numlines {
        perl -pe '$_ = qq($. $_)' $args
    }
    

    它适用于文件作为参数( numlines my_file.pl ),但不适用于来自管道的输入( cat my_file.pl | numlines )。

    有没有办法编写函数以使其双向工作?

    澄清一下 - 我可以使用 bat 文件来做到这一点。例如, numlines.bat 包含
    @perl -pe "$_ = qq($. $_)" %*
    

    但是必须调用 cmd.exe 和 bat 文件的一般丑陋(即“终止批处理作业(Y/N)?”当您按下 CTRL-C :-() 时的提示让我希望在 Powershell 中有一个类似简单的解决方案。 .

    根据下面理查德的建议,我尝试了:
    function test {
      [CmdletBinding()]
    
      param(
        [Parameter(mandatory=$true, ValueFromPipeline=$true)]
        $data
      )
    
      process {
        perl -pe '$_ = qq($. $_)'
      }
    }
    

    如果我这样做 test file.txt (我希望以与 perl -pe '$_ = qq($. $_)' file.txt 相同的方式有效运行)该函数运行,但等待标准输入上的数据而不是处理 file.txt .当我尝试 cat file.txt | test 时也会发生同样的事情- 我希望其行为与 cat file.txt | perl -pe '$_ = qq($. $_)' 相同.

    最佳答案

    基础知识:高级功能可以做的比标准功能更多

    Is there a way to write the function so that it works both ways?


    是的,使用 advanced functions ,将为每个输入对象调用进程 block 。
  • 您需要指定 [CmdletBinding] param 之前的开始处堵塞。
  • 您需要一个接受管道输入的参数,这是通过 Parameter 完成的。该参数的属性。

  • 像这样:
    function ReadInput {
      [CmdletBinding]
      param(
        [Parameter(mandatory=$true, ValueFromPipeline=$true)]
        $data
      )
    
      process {
        "Input was: $data";
      }
    }
    

    更好地在本地做事

    head -1 (Print the first line of a file)


    First Select-Object的参数: ... | Select -f 1 | ....只会通过第一个对象。

    sed $d (Drop the last line of a file)


    这个更难......本质上是一个跟踪是否有另一行的函数。

    perl -pe '$_ = qq($. $_)' (Number lines in a file)


    您需要Measure-Object ,如果没有其他参数,它将计算它在管道上接收到的对象的数量。

    为什么它不起作用
    (基于扩展问题)
    这有两个部分:
    首先:您需要将绑定(bind)到管道的参数的值传递给您的操作。所以:
    process {
      perl -pe '$_ = qq($. $_)'
    }
    

    应该
    process {
      $data | perl -pe '$_ = qq($. $_)'
    }
    
    第二:这可能不适用于您的许多实用程序,因为每次 process block 被执行 管道的一个新实例将被执行,包括一个新的 sed 的调用(等)对于管道上的每个对象,从而失去您通常期望它从一行到下一行保持的任何状态。
    这周围有两条路线。首先,您可以使用可步进的管道,这是一个高级主题(唯一体面的介绍是在 Bruce Payette(他完成了大部分 PSH 语言的设计和实现)的 Windows PowerShell in Action 第二版一书中)。
    第二:做事原生。例如。文件中的行数(不使用 Measure-Object ):
    function Get-ObjectCount {
      [CmdletBinding]
      param(
        [Parameter(mandatory=$true, ValueFromPipeline=$true)]
        [object[]]$data   # Accept an array...
      )
    
      begin {
        $count = 0  # Not strictly needed: PSH will default this.
      }
    
      process {
        $count += $data.length
      }
    
      end {
        $count
      }
    }
    
    这也会快得多(无需创建另一个进程。
    只要您专注于将 PSH 作为包装器,您就会发现您正在两全其美:失去 *ix 类型工具的灵 active (PSH 的执行模型不同:在一个进程中协作工具)并失去PSH 的灵 active (PSH 适用于类型化对象而不是字符串)。

    关于powershell - 如何编写包装 sed/perl/etc 命令的 powershell 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14607249/

    相关文章:

    deployment - 如何从 psake 执行 .bat 文件?

    powershell - 对 Powershell 脚本中的所有错误调用函数

    powershell - Powershell将字节转换为GB

    powershell - 如何在 psake 中调用 exec 到具有可变路径的可执行文件?

    powershell - 为什么我的 Azure 存储帐户中没有主键

    PowerShell Start-Service 无休止地运行

    windows - 使用 Powershell 实现 IE 自动化

    visual-studio - 从自定义项目模板执行 PowerShell 脚本

    powershell - 确定 Windows-shell 命令在 Powershell 中完成的时间

    powershell - 使用 Powershell 在没有提示的情况下自动删除文件