我经常使用一些sed / perl / etc“one-liner”命令:
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($. $_)" %*
但是当你点击CTRL-C时,不得不调用cmd.exe和bat文件的一般丑陋(“终止批处理作业(Y / N)?”提示),这让我想要一个类似的简单解决方案的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($. $_)'
完全相同。
答案 0 :(得分:5)
有没有办法编写函数以便它可以双向工作?
是的,使用advanced functions,将为每个输入对象调用过程块。
param
阻止之前的开头指定[CmdletBinding]
。Parameter
属性完成的。像这样:
function ReadInput {
[CmdletBinding]
param(
[Parameter(mandatory=$true, ValueFromPipeline=$true)]
$data
)
process {
"Input was: $data";
}
}
head -1(打印文件的第一行)
查看First
的{{1}}参数:Select-Object
只会传递第一个对象。
sed $ d(删除文件的最后一行)
这个更难......本质上是一个跟踪是否有另一条线的功能。
perl -pe'$ _ = qq($。$ _)'(文件中的数字行)
您需要... | Select -f 1 | ....
,没有其他参数将计算它在管道上接收的对象数量。
(基于扩展的问题)
这有两个部分:
首先:您需要将绑定到管道的参数值传递给您的操作。所以:
Measure-Object
应该是
process {
perl -pe '$_ = qq($. $_)'
}
第二:这可能不适用于很多实用程序,因为每次执行process {
$data | perl -pe '$_ = qq($. $_)'
}
块时,都会执行新的管道实例,包括process
的新调用(等)对于管道上的每个对象,从而丢失您通常期望从一行到下一行保持的任何状态。
这有两条路线。首先,您可以使用可移植管道,这是一个高级主题(唯一不错的选择是在书中 Windows PowerShell in Action 第二版由Bruce Payette(他做了大部分工作) PSH语言设计和实现))。
第二:本地做事。例如。文件中的行数(不使用sed
):
Measure-Object
这也会快得多(不需要创建另一个流程。
只要你专注于PSH作为包装器,你就会发现你是两个世界中最糟糕的:失去了* ix类型工具的灵活性(PSH的执行模型不同:在一个过程中合作工具) 和失去了PSH的灵活性(PSH适用于类型对象而不是字符串)。
答案 1 :(得分:0)
解决方案的关键似乎是在函数中使用$ args(用于命令行参数)和$ input(用于管道输入),如下所示:
function wrapper {
$input | WRAPPED_COMMAND_HERE $args
}
因此,例如,对数字行的perl命令的情况如下所示
PS> function nl {
>> $input | perl -pe '$_ = qq($. $_)' $args
>> }
>>
PS> nl test.txt
1 This is some
2 test data
PS> type test.txt | nl
1 This is some
2 test data