在 PowerShell 中模拟 bash ls -ltr pipe grep

Emulate bash ls -ltr pipe grep in PowerShell

提问人:capser 提问时间:5/10/2023 最后编辑:marc_scapser 更新时间:5/24/2023 访问量:48

问:

我使用下面的脚本来模拟 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 参数传递 命令行参数

评论

0赞 Mathias R. Jessen 5/10/2023
我假设你是专门为文件名而写的?grep
0赞 jdweng 5/10/2023
$null不是字符串。不要使用空字符串 “” 或 [system.string]::Empty 来代替$null
0赞 capser 5/10/2023
@MathiasR.Jessen,我正在搜索根目录中的所有*html文件。第二个参数“param2”应缩小搜索范围。我将其输出到文本文件以简化剪切和粘贴
0赞 capser 5/10/2023
当我有 twp 参数时,这有效——有时我只需要一个参数——这会破坏这个脚本——当我只有一个参数时,我使用另一个脚本。

答:

0赞 Mathias R. Jessen 5/10/2023 #1

数组在 PowerShell 中非常简单 - 要将参数声明为字符串数组,请键入它:[string[]]

param(
  [string[]]$SearchTerms
)

现在,您只需要对调用方提供的每个术语重复字符串匹配操作 - 我们可以对相关属性使用运算符,而不是调用:-matchSelect-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
1赞 mklement0 5/11/2023 #2

我知道如何在 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]
  • 命名参数的使用:

    • 声明的参数可以以更自我描述的方式进行绑定(传递参数),方法是在它前面加上参数的名称;例如,如果你定义了一个参数,一个参数可以作为而不是仅仅传递给它,后者是一个位置参数,其相对于其他此类参数的位置决定了它绑定到哪个参数。$Patternfoo-Pattern foofoo
  • 鲁棒性:

    • 您可以将参数设置为必填参数,即要求将参数传递给它们;如果不这样做,系统会提示您输入值,但请注意,此提示功能的用户体验很差 - 请参阅此答案以获取讨论和替代方案。

    • 如果将属性放在块上方或使用至少一个特定于参数的属性,则脚本或函数将隐式变为高级属性,在这种情况下,参数绑定器将确保只能传递绑定到声明参数的参数。[CmdletBinding()]param(...)[Parameter()]

    • 如果没有它,仍然支持无法绑定到声明参数的参数,并收集在(然后包含这些所谓的未绑定参数)。$args


PowerShell 使声明数组参数变得容易 - 例如 声明字符串数组。[string[]] $Pattern

  • 默认情况下,它们还需要一个数组作为它们的参数,这意味着一个参数,其数组元素在调用时;例如,要传递 patterns 和 ,您必须使用
    - 注意必需的
    foobarPattern 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