PowerShell中与rm -f等效且忽略不存在文件的命令是什么?

19

背景

我有一个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 IgnoreRemove-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 等效的命令,满足上述所有要求?

3个回答

21

对我来说,最简单的解决方案是:

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'

2

仅使用该 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".
#>

当然,如果你想让事情发生,就要删除/注释掉-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".
#>

0
我们需要使用Test-Path $item来验证$item是否存在。
  • $item不存在时,Remove-Item $item将以错误结束。

因此,下面的quiet_rm()函数被设计为模拟linux的rm -rf file/folder命令。

  • 即使$item不存在,也不会报告错误消息。
# Remove a file or folder quietly
# Like linux "rm -rf"
function quiet_rm($item)
{
  if (Test-Path $item) {
    echo "  Removing $item"
    Remove-Item $item  -r -force
  }
}

echo "Clear folder and files"
quiet_rm .\build\
quiet_rm   build.gradle
quiet_rm  .gradle
quiet_rm   gradle
quiet_rm   gradle.properties

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接