获取内容不在括号内-拒绝进程访问

时间:2019-06-19 16:32:50

标签: powershell

使用Get-Content从文件中删除空格时:

$file = "C:\Folder\MyFile001.txt"
Get-Content -Path $file | ? { -not [string]::IsNullOrWhiteSpace($_) } | Set-Content -Path $file

显示错误消息'Set-Content:该进程无法访问文件'...',因为它正在被另一个进程使用。

解决方法是在Get-Content中使用括号:

(Get-Content -Path $file) | ...

这是什么原因?我想了解括号的区别,以及这是否适用于其他cmdlet。

2 个答案:

答案 0 :(得分:4)

当cmdlet在管道上输出某些内容时,将在处理cmdlet的下一个输出之前执行管道。因此,当您的字符串沿流向Set-Content的管道进行操作时,Get-Content仍处于活动状态(输出文件处于打开状态),等待其继续执行。但是,当将表达式包装在()中时,所有输出都将收集到一个数组中,然后将其向下推入管道。 Get-Content完成并关闭文件。为了演示,请考虑以下功能:

function get-10dates { $count = 0; while($count -lt 10){ get-date; $count += 1 }}

在运行它并将其通过管道传递到foreach循环时:

get-10dates | foreach { $_; sleep -Seconds 1 }

您将得到以下输出,由于foreach中的sleep,每个日期都延迟了一秒钟:

# ~> get-10dates | foreach { $_; sleep -Seconds 1 }

June 19, 2019 9:58:36 AM
June 19, 2019 9:58:37 AM
June 19, 2019 9:58:38 AM
June 19, 2019 9:58:39 AM
June 19, 2019 9:58:40 AM
June 19, 2019 9:58:41 AM
June 19, 2019 9:58:42 AM
June 19, 2019 9:58:43 AM
June 19, 2019 9:58:44 AM
June 19, 2019 9:58:45 AM

现在,如果将函数包装在()中。您会看到所有10个日期都在一次传递到管道之前立即创建(在1秒内):

# ~> (get-10dates) | foreach { $_; sleep -Seconds 1 }

June 19, 2019 9:58:53 AM
June 19, 2019 9:58:53 AM
June 19, 2019 9:58:53 AM
June 19, 2019 9:58:53 AM
June 19, 2019 9:58:53 AM
June 19, 2019 9:58:53 AM
June 19, 2019 9:58:53 AM
June 19, 2019 9:58:53 AM
June 19, 2019 9:58:53 AM
June 19, 2019 9:58:53 AM

答案 1 :(得分:0)

括号在Powershell中的工作方式与在代数中一样。

种类。

PowerShell首先在括号中执行该命令,然后尝试将其与要运行的位置进行类型匹配。在这种情况下,您要告诉它完成Get-Content的运行并将缓冲区读入内存,然后再继续执行下一个命令,而不是通过管道流式传输所有内容。

这与BaSH的工作方式类似,在其中您使用类似的内容(假设“ service.txt”包含一行写着apache的行):

Service $(cat /etc/service.txt) Stop
>> Service apache stop 

将在$()中执行命令,并在运行其余命令之前将其作为文本返回。

在PowerShell中,您可以使用括号的类型匹配功能执行整洁的操作,例如使其仅返回单个对象属性:

(Get-ChildItem -filter "*.pdf" -Path .\Projects).FullName 
>> C:\Users\ncf\Projects\Documentation.pdf