rm -f 等效于忽略不存在文件的 PowerShell
rm -f equivalent for PowerShell that ignore nonexistent files
背景
我有一个 PowerShell 脚本,可以将一些结果写入文件。
- 我想在
Remove-Item
脚本开始时自动删除结果文件。
- 您可以手动删除结果文件,所以即使结果文件不存在,我也不想显示错误消息。
- 我想在脚本由于其他原因无法删除结果文件时显示错误消息,例如文件已锁定。
您可以在类 Unix 系统中使用 rm -f
满足上述所有要求。
问题
首先我尝试了Remove-Item -Force
,但它无法忽略不存在的文件(参见rm -f
忽略不存在的文件)。
PS C:\tmp> Remove-Item C:\tmp\foo.txt -Force
Remove-Item : Cannot find path 'C:\tmp\foo.txt' because it does not exist.
At line:1 char:1
+ Remove-Item C:\tmp\foo.txt -Force
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:\tmp\foo.txt:String) [Remove-Item], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.RemoveItemCommand
接下来,我尝试了 Remove-Item -ErrorAction Ignore
和 Remove-Item -ErrorAction SilentlyContinue
,但是它们在删除文件失败时不显示错误消息(参见 rm -f
显示如下错误消息rm: cannot remove 'foo.txt': Operation not permitted
在这种情况下)。
PS C:\tmp> $file = [System.IO.File]::Open('C:\tmp\foo.txt',[System.IO.FileMode]::Open,[System.IO.FileAccess]::Read,[System.IO.FileShare]::None)
PS C:\tmp> Remove-Item C:\tmp\foo.txt -ErrorAction Ignore
# I expected it shows an error because it couldn't remove the file because of the lock, but it showed nothing
PS C:\tmp> $file = [System.IO.File]::Open('C:\tmp\foo.txt',[System.IO.FileMode]::Open,[System.IO.FileAccess]::Read,[System.IO.FileShare]::None)
PS C:\tmp> Remove-Item C:\tmp\foo.txt -ErrorAction SilentlyContinue
# I expected it shows an error because it couldn't remove the file because of the lock, but it showed nothing
问题
在满足上述所有要求的 PowerShell 中是否有 rm -f
等价物?
对我来说,最简单的解决方案是:
if (test-path $file) {
remove-item $file
}
我也遇到过这种情况。 $error[0] 总是最新的错误。
remove-item $file -erroraction silentlycontinue
if ($error[0] -notmatch 'does not exist') {
write-error $error[0] # to standard error
}
我认为您也可以使用 try/catch,但有特定的例外情况。这是一个例子。我通过制表符补全发现了异常。但是脚本会因其他未捕获的异常而停止。此错误通常不会停止。
try { remove-item foo -erroraction stop }
catch [System.Management.Automation.ItemNotFoundException] { $null }
'hi'
您不能单独使用该 cmdlet 执行此操作。您必须为错误提供额外的逻辑。
'D:\temp\abc.txt', 'D:\Temp\hw.txt', 'D:\Temp\nonexistent.txt.', 'D:\Temp\book1.csv' |
ForEach{
try {Remove-Item -Path $PSitem -WhatIf -ErrorAction Stop}
catch {Write-Warning -Message $PSItem.Exception.Message}
}
# Results
<#
What if: Performing the operation "Remove File" on target "D:\temp\abc.txt".
What if: Performing the operation "Remove File" on target "D:\Temp\hw.txt".
WARNING: Cannot find path 'D:\Temp\nonexistent.txt.' because it does not exist.
What if: Performing the operation "Remove File" on target "D:\Temp\book1.csv".
#>
您应该在所有代码(交互式和脚本)中利用错误处理。
您可以将任何屏幕输出发送到 $null、Out-Null 或 [void] 以防止它进入屏幕,但仍然知道它发生了。
对于您要求的用例,您将需要多个逻辑(try/catch、if/then)语句。
所以,类似这个修改后的包装函数:
function Remove-ItemNotFileLocked
{
[cmdletbinding(SupportsShouldProcess)]
[Alias('rinf')]
param
(
[parameter(Mandatory = $true)][string]$FullFilePath
)
$TargetFile = New-Object System.IO.FileInfo $FullFilePath
if ((Test-Path -Path $FullFilePath) -eq $false) {return $false}
try
{
$TargetFileStream = $TargetFile.Open([System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None)
if ($TargetFileStream)
{
$TargetFileStream.Close()
Remove-Item -Path $FullFilePath
}
$false
}
catch
{
$true
}
}
'D:\temp\abc.txt', 'D:\Documents\Return To Sender.docx','D:\Temp\nonexistent.txt.' |
ForEach {Remove-ItemNotFileLocked -FullFilePath $PSItem -WhatIf}
# Results
<#
What if: Performing the operation "Remove File" on target "D:\temp\abc.txt".
True
False
#>
注意事项:记事本等文本编辑器不会锁定文件。
- 第一条消息显示记事本文件已打开,但可以删除
- 第二个显示打开并锁定的 Word 文档
- 第三个显示的是一个文本文件,系统上没有
如果我不想要那种屏幕噪音,那么...
注释掉那些 $false 和 $True 语句,它们用于调试和验证工作。
'D:\temp\abc.txt', 'D:\Documents\Return To Sender.docx','D:\Temp\nonexistent.txt.' |
ForEach {$null = Remove-ItemNotFileLocked -FullFilePath $PSItem -WhatIf}
# Results
<#
What if: Performing the operation "Remove File" on target "D:\temp\abc.txt".
#>
当然,remove/comment 输出 -WhatIf 让事情发生,噪音也会消失。
如果您不想使用某个函数,那么此代码块应该可以解决您的用例。
# Remove non-Locked file and show screen output
'D:\temp\abc.txt', 'D:\Documents\Return To Sender.docx','D:\Temp\nonexistent.txt.' |
ForEach{
try
{
$TargetFile = (New-Object System.IO.FileInfo $PSitem).Open(
[System.IO.FileMode]::Open,
[System.IO.FileAccess]::ReadWrite,
[System.IO.FileShare]::None
)
$TargetFile.Close()
Remove-Item -Path $PSItem -WhatIf
}
catch [System.Management.Automation.ItemNotFoundException]{$PSItem.Exception.Message}
catch {$PSItem.Exception.Message}
}
# Results
<#
What if: Performing the operation "Remove File" on target "D:\temp\abc.txt".
Exception calling "Open" with "3" argument(s): "The process cannot access the file 'D:\Documents\Return To Sender.docx' because it is being used by another process."
Exception calling "Open" with "3" argument(s): "Could not find file 'D:\Temp\nonexistent.txt'."
#>
# Remove non-Locked file and silence screen output
'D:\temp\abc.txt', 'D:\Documents\Return To Sender.docx','D:\Temp\nonexistent.txt.' |
ForEach{
try
{
$TargetFile = (New-Object System.IO.FileInfo $PSitem).Open(
[System.IO.FileMode]::Open,
[System.IO.FileAccess]::ReadWrite,
[System.IO.FileShare]::None
)
$TargetFile.Close()
Remove-Item -Path $PSItem -WhatIf
}
catch [System.Management.Automation.ItemNotFoundException]{$null = $PSItem.Exception.Message}
catch {$null = $PSItem.Exception.Message}
}
# Results
<#
What if: Performing the operation "Remove File" on target "D:\temp\abc.txt".
#>
背景
我有一个 PowerShell 脚本,可以将一些结果写入文件。
- 我想在
Remove-Item
脚本开始时自动删除结果文件。 - 您可以手动删除结果文件,所以即使结果文件不存在,我也不想显示错误消息。
- 我想在脚本由于其他原因无法删除结果文件时显示错误消息,例如文件已锁定。
您可以在类 Unix 系统中使用 rm -f
满足上述所有要求。
问题
首先我尝试了Remove-Item -Force
,但它无法忽略不存在的文件(参见rm -f
忽略不存在的文件)。
PS C:\tmp> Remove-Item C:\tmp\foo.txt -Force
Remove-Item : Cannot find path 'C:\tmp\foo.txt' because it does not exist.
At line:1 char:1
+ Remove-Item C:\tmp\foo.txt -Force
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:\tmp\foo.txt:String) [Remove-Item], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.RemoveItemCommand
接下来,我尝试了 Remove-Item -ErrorAction Ignore
和 Remove-Item -ErrorAction SilentlyContinue
,但是它们在删除文件失败时不显示错误消息(参见 rm -f
显示如下错误消息rm: cannot remove 'foo.txt': Operation not permitted
在这种情况下)。
PS C:\tmp> $file = [System.IO.File]::Open('C:\tmp\foo.txt',[System.IO.FileMode]::Open,[System.IO.FileAccess]::Read,[System.IO.FileShare]::None)
PS C:\tmp> Remove-Item C:\tmp\foo.txt -ErrorAction Ignore
# I expected it shows an error because it couldn't remove the file because of the lock, but it showed nothing
PS C:\tmp> $file = [System.IO.File]::Open('C:\tmp\foo.txt',[System.IO.FileMode]::Open,[System.IO.FileAccess]::Read,[System.IO.FileShare]::None)
PS C:\tmp> Remove-Item C:\tmp\foo.txt -ErrorAction SilentlyContinue
# I expected it shows an error because it couldn't remove the file because of the lock, but it showed nothing
问题
在满足上述所有要求的 PowerShell 中是否有 rm -f
等价物?
对我来说,最简单的解决方案是:
if (test-path $file) {
remove-item $file
}
我也遇到过这种情况。 $error[0] 总是最新的错误。
remove-item $file -erroraction silentlycontinue
if ($error[0] -notmatch 'does not exist') {
write-error $error[0] # to standard error
}
我认为您也可以使用 try/catch,但有特定的例外情况。这是一个例子。我通过制表符补全发现了异常。但是脚本会因其他未捕获的异常而停止。此错误通常不会停止。
try { remove-item foo -erroraction stop }
catch [System.Management.Automation.ItemNotFoundException] { $null }
'hi'
您不能单独使用该 cmdlet 执行此操作。您必须为错误提供额外的逻辑。
'D:\temp\abc.txt', 'D:\Temp\hw.txt', 'D:\Temp\nonexistent.txt.', 'D:\Temp\book1.csv' |
ForEach{
try {Remove-Item -Path $PSitem -WhatIf -ErrorAction Stop}
catch {Write-Warning -Message $PSItem.Exception.Message}
}
# Results
<#
What if: Performing the operation "Remove File" on target "D:\temp\abc.txt".
What if: Performing the operation "Remove File" on target "D:\Temp\hw.txt".
WARNING: Cannot find path 'D:\Temp\nonexistent.txt.' because it does not exist.
What if: Performing the operation "Remove File" on target "D:\Temp\book1.csv".
#>
您应该在所有代码(交互式和脚本)中利用错误处理。 您可以将任何屏幕输出发送到 $null、Out-Null 或 [void] 以防止它进入屏幕,但仍然知道它发生了。
对于您要求的用例,您将需要多个逻辑(try/catch、if/then)语句。
所以,类似这个修改后的包装函数:
function Remove-ItemNotFileLocked
{
[cmdletbinding(SupportsShouldProcess)]
[Alias('rinf')]
param
(
[parameter(Mandatory = $true)][string]$FullFilePath
)
$TargetFile = New-Object System.IO.FileInfo $FullFilePath
if ((Test-Path -Path $FullFilePath) -eq $false) {return $false}
try
{
$TargetFileStream = $TargetFile.Open([System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None)
if ($TargetFileStream)
{
$TargetFileStream.Close()
Remove-Item -Path $FullFilePath
}
$false
}
catch
{
$true
}
}
'D:\temp\abc.txt', 'D:\Documents\Return To Sender.docx','D:\Temp\nonexistent.txt.' |
ForEach {Remove-ItemNotFileLocked -FullFilePath $PSItem -WhatIf}
# Results
<#
What if: Performing the operation "Remove File" on target "D:\temp\abc.txt".
True
False
#>
注意事项:记事本等文本编辑器不会锁定文件。
- 第一条消息显示记事本文件已打开,但可以删除
- 第二个显示打开并锁定的 Word 文档
- 第三个显示的是一个文本文件,系统上没有
如果我不想要那种屏幕噪音,那么... 注释掉那些 $false 和 $True 语句,它们用于调试和验证工作。
'D:\temp\abc.txt', 'D:\Documents\Return To Sender.docx','D:\Temp\nonexistent.txt.' |
ForEach {$null = Remove-ItemNotFileLocked -FullFilePath $PSItem -WhatIf}
# Results
<#
What if: Performing the operation "Remove File" on target "D:\temp\abc.txt".
#>
当然,remove/comment 输出 -WhatIf 让事情发生,噪音也会消失。
如果您不想使用某个函数,那么此代码块应该可以解决您的用例。
# Remove non-Locked file and show screen output
'D:\temp\abc.txt', 'D:\Documents\Return To Sender.docx','D:\Temp\nonexistent.txt.' |
ForEach{
try
{
$TargetFile = (New-Object System.IO.FileInfo $PSitem).Open(
[System.IO.FileMode]::Open,
[System.IO.FileAccess]::ReadWrite,
[System.IO.FileShare]::None
)
$TargetFile.Close()
Remove-Item -Path $PSItem -WhatIf
}
catch [System.Management.Automation.ItemNotFoundException]{$PSItem.Exception.Message}
catch {$PSItem.Exception.Message}
}
# Results
<#
What if: Performing the operation "Remove File" on target "D:\temp\abc.txt".
Exception calling "Open" with "3" argument(s): "The process cannot access the file 'D:\Documents\Return To Sender.docx' because it is being used by another process."
Exception calling "Open" with "3" argument(s): "Could not find file 'D:\Temp\nonexistent.txt'."
#>
# Remove non-Locked file and silence screen output
'D:\temp\abc.txt', 'D:\Documents\Return To Sender.docx','D:\Temp\nonexistent.txt.' |
ForEach{
try
{
$TargetFile = (New-Object System.IO.FileInfo $PSitem).Open(
[System.IO.FileMode]::Open,
[System.IO.FileAccess]::ReadWrite,
[System.IO.FileShare]::None
)
$TargetFile.Close()
Remove-Item -Path $PSItem -WhatIf
}
catch [System.Management.Automation.ItemNotFoundException]{$null = $PSItem.Exception.Message}
catch {$null = $PSItem.Exception.Message}
}
# Results
<#
What if: Performing the operation "Remove File" on target "D:\temp\abc.txt".
#>