提问人:capser 提问时间:5/10/2023 最后编辑:marc_scapser 更新时间:5/24/2023 访问量:48
在 PowerShell 中模拟 bash ls -ltr pipe grep
Emulate bash ls -ltr pipe grep in PowerShell
问:
我使用下面的脚本来模拟 bash
ls -ltr /www/root/*html| grep 'string' | grep 'narrower search string'
我在记事本中打开结果 - 因为从 PowerShell 终端剪切和粘贴非常困难。
当有两个参数时,它工作正常 - 但是当我只有一个参数时,它不能很好地工作,例如:
ls -ltr /www/root/*html| grep 'string'
我知道如何在 bash 中使用@ARGS。但是,在 PowerShell 中没有看到任何可比的东西。我没有看到任何类型的数组来验证 PowerShell 中的行参数。
param(
[parameter()]
[string] $param1 = $null ,
[string] $param2 = $null
)
$makecurrent = '(dir sample_file.txt).LastWriteTime = Get-Date'
$timestr = get-date -f 'MMddHHmmss'
get-childitem -path "C:\www\root\*html" -Name | sort LastWriteTime -descending | out-file -filepath "c:\temp\lsfile$timestr.txt"
select-string -path "c:\temp\lsfile$timestr.txt" -pattern "$param1" | out-file -filepath "c:\temp\$param1$timestr.txt"
select-string -path "c:\temp\$param1$timestr.txt" -pattern "$param2" | out-file -filepath "c:\temp\$param2$timestr.txt"
$makecurrent | add-content -path "c:\temp\$param2$timestr.txt"
start "c:\temp\$param2$timestr.txt"
我正在尝试让 PowerShell 脚本接受一个或两个参数。
答:
数组在 PowerShell 中非常简单 - 要将参数声明为字符串数组,请键入它:[string[]]
param(
[string[]]$SearchTerms
)
现在,您只需要对调用方提供的每个术语重复字符串匹配操作 - 我们可以对相关属性使用运算符,而不是调用:-match
Select-String
param(
[string[]]$SearchTerms
)
$items = Get-ChildItem -path "C:\www\root\*html" -Name |Sort-Object LastWriteTime -Descending
foreach($term in $SearchTerms){
$items = $items |Where-Object { $_.Name -match $term }
}
return $items
我知道如何在 bash 中使用。但是,在 powershell 中没有看到任何可比的东西。我没有看到任何类型的数组来验证 powershell 中的行参数。
@ARGS
PowerShell 的自动$args
变量等效于 Bash 的 () 参数:两者都包含在数组中收集的单独传递的参数。$@
$*
主要区别在于:
$args
仅包含参数(而不是包含调用的脚本名称或路径的第一个元素,如在 Bash 中,${@:0:1}
)因此,它包含第一个参数(比较)、第二个参数(比较)等。
$args[0]
"${@:1:1}"
$args[1]
"${@:2:1}"
$args.Count
包含传递的参数数(相当于 Bash 的 )。$#
这意味着,如果要接受不受约束的、开放式的参数数量,则不需要严格声明参数(通过块),这将简化脚本:param(...)
# ... no param() block needed
# ...
# Simply pass $args - containing all arguments -
# directly to Select-String's -Pattern parameter
select-string -path "c:\temp\lsfile$timestr.txt" -pattern $args |
out-file -filepath "c:\temp\$param1$timestr.txt"
更新:
后来我突然想到,通过链接调用,您正在寻找连接逻辑,即仅包含所有模式的行;相比之下,将多个模式传递给单个
Select-String
应用析取逻辑,即它查找包含任何模式的行。grep
由于这篇文章主要是关于参数声明和处理的,我不会解决这方面的问题,但我可以向你指出一个辅助函数,该函数可从这个 Gist 中获得,它提供了所需的逻辑;您可以使用以下命令直接安装它:
Select-StringAll
irm https://gist.github.com/mklement0/356acffc2521fdd338ef9d6daf41ef07/raw/Select-StringAll.ps1 | iex
我个人可以保证这样做是安全的,但首先查看源代码总是一个好主意)。
如果您更愿意自己实现逻辑,请参阅 Mathias R. Jessen 的答案。
但是,出于以下原因,您可能需要声明参数:
数据类型的使用:
- 声明的参数可以声明为特定的 .NET 数据类型,例如 () 或 (
System.DateTime
),PowerShell 的参数绑定程序会自动强制给定参数 (value) 属于该类型或可以转换为该类型。[int]
System.Int32
[datetime]
- 声明的参数可以声明为特定的 .NET 数据类型,例如 () 或 (
命名参数的使用:
- 声明的参数可以以更自我描述的方式进行绑定(传递参数),方法是在它前面加上参数的名称;例如,如果你定义了一个参数,一个参数可以作为而不是仅仅传递给它,后者是一个位置参数,其相对于其他此类参数的位置决定了它绑定到哪个参数。
$Pattern
foo
-Pattern foo
foo
- 声明的参数可以以更自我描述的方式进行绑定(传递参数),方法是在它前面加上参数的名称;例如,如果你定义了一个参数,一个参数可以作为而不是仅仅传递给它,后者是一个位置参数,其相对于其他此类参数的位置决定了它绑定到哪个参数。
鲁棒性:
PowerShell 使声明数组参数变得容易 - 例如 声明字符串数组。[string[]] $Pattern
默认情况下,它们还需要一个数组作为它们的参数,这意味着一个参数,其数组元素在调用时用
分
隔;例如,要传递 patterns 和 ,您必须使用
- 注意必需的foo
bar
Pattern foo, bar
,
要获得与自动
$args
变量等效的行为 - 即在数组中收集单独的参数,您可以使用[Parameter(ValueFromRemainingArguments)]
属性来修饰目标参数,它会自动收集该参数中的所有位置参数,同时允许其他参数(如果有)按名称绑定。您仍然可以选择按名称绑定此类参数,但是在这种情况下,您必须再次传递单个数组作为参数。
换言之:您可以通过以下两种方式之一绑定名为 的参数:
ValueFromRemainingArguments
-Pattern
命名,带有数组(注意):
,
Some-Command -Pattern foo, bar
位置(未命名),带有单个参数:
Some-Command foo bar
应用于脚本:
param(
# Declare -Pattern as an array of strings that can also
# be bound with individual, positional arguments.
[Parameter(Mandatory, ValueFromRemainingArguments)]
[string[]] $Pattern
)
# ...
# Simply pass $Pattern - containing all patterns -
# directly to Select-String's -Pattern parameter
select-string -path "c:\temp\lsfile$timestr.txt" -pattern $Pattern |
out-file -filepath "c:\temp\$param1$timestr.txt"
虽然比不声明参数更复杂,但这种形式的脚本具有以下优点:
它强制传递至少一个模式。
它使您可以自由地声明其他参数,例如可选参数(标志),例如,这不会干扰通过位置参数收集模式。
[switch]
-CaseSensitive
通过使用属性,您的脚本现在是一个高级脚本,它提供对常见参数(如 或)的自动支持。
[Parameter()]
-Verbose
-OutVariable
评论
grep