有子目录为什么"get-childItem -recurse | select-string foo"不报错?

Why does "get-childItem -recurse | select-string foo" not result in an error if there are subdirectories?

尝试在目录上使用 select-string 导致错误:

PS C:\> select-string pattern P:\ath\to\directory
select-string : The file P:\ath\to\directory cannot be read: Access to the path 'P:\ath\to\directory' is denied.

但是,当我使用 get-childItem -recurse 时,命令完成时没有问题:

PS C:\> get-childItem -recurse P:\ath\to | select-string pattern

这让我感到惊讶,因为 get-childItem recurse 还会将目录传递到管道中。因此,我假设 select-string 在处理第一个目录时会引发相同的错误。

既然不是这样,我想知道目录在管道中的位置或如何被过滤掉。

Select-String-Path 参数需要文件路径:

-Path

Specifies the path to the files to search. Wildcards are permitted. The default location is the local directory.

Specify files in the directory, such as log1.txt, *.doc, or .. If you specify only a directory, the command fails.

这就是当您将目录路径传递给 -Path 参数时出现错误的原因。

当您将对象通过管道传输到 Select-String 时,它们不一定需要可以映射到 Select-String-PathPath 属性:

You can pipe any object that has a ToString method to Select-String.

因此您还可以将原始字符串通过管道传输到 Select-String:

'test' | Select-String -Pattern 'test'

这一行将 return test.

Get-ChildItem returns System.IO.FileInfoSystem.IO.DirectoryInfo 类型的对象。 Select-String 将使用 System.IO.FileInfoPath 属性来解析文件的内容,并将使用 System.IO.DirectoryInfo 的字符串表示来准确解析此字符串表示(路径本身).这就是为什么您不会在管道中出现错误。

New-Item -Name 'test' -Type Directory | Select-String -Pattern 'test'

这一行将return指向刚刚创建的目录的路径test

TL;DR: 物体魔法。

Get-Childitem为运行时,它将return一个对象集合。这将传递给 Select-String。该 cmdlet 的 source 在 Github 上可用。有一个 ProcessRecord() 方法可以处理输入对象。它包含一些对象类型检查以及这些是否是目录。像这样,

if (_inputObject.BaseObject is FileInfo fileInfo)
...
if (expandedPathsMaybeDirectory && Directory.Exists(filename))
...

因此,Get-Child 的集合包含 DirectoryInfoFileInfo 对象并不重要;该 cmdlet 足够聪明,可以弄清楚它正在尝试使用什么。