shell - 在powershell中检查文件是否可读且正常

标签 shell powershell powershell-3.0 powershell-4.0

我是 powershell 新手,我想检查文件是否可读且正常。在 unix 中,我们可以使用 -f 和 -r 在一行中完成此操作。例如,以下 shell 脚本函数接受文件名作为参数并检查文件的可读性和规律性,与此等效的 powershell 是什么?

_ChkRegularFile_R()        # checks whether a file is regular and readable
{   
    _CRFRfilename=$1                    # name of the file to be checked

_CRFRsts=1                          # default is error

if [ -f "$_CRFRfilename" ]
then
    if [ -r "$_CRFRfilename" ]
    then
        _CRFRsts=0        # success: regular file is readable
    fi
fi

return $_CRFRsts
}

最佳答案

要测试文件是否可读,您可以尝试打开它。如果出现错误,则该文件不可读。您需要根据需要捕获或捕获异常或因错误而停止。请记住,Windows 会锁定打开以进行写入的文件,因此应用程序需要预料到它们有时无法打开文件。

如果确实有必要,您可以使用类似的方法来测试是否可以读取文件:

try {
    [System.IO.File]::OpenRead($FullPathName).Close()
    $Readable = $true
}
catch {
    $Readable = $false        
}

这是为了测试您是否可以写入文件:

try {
    [System.IO.File]::OpenWrite($FullPathName).Close()
    $Writable = $true
}
catch {
    $Writable = $false        
}

如果您确实需要的话,该逻辑很容易包装到函数中。

就文件类型而言,Windows 文件系统中的几乎所有内容都是普通文件或目录,因为 Windows 没有“一切都是文件”约定。所以,通常你可以按如下方式进行测试:

# Test if file-like
Test-Path -Path $Path -Leaf

# Test if directory-like
Test-Path -Path $Path -Container

如果您正在使用 FileInfoDirectoryInfo 对象(即 Get-Item 的输出,Get- ChildItem,或代表文件或目录的类似对象),您将拥有 PSIsContainer 属性,该属性将告诉您该项目是文件还是目录。

这可能涵盖了 99.999% 的情况。


但是,如果您需要知道某个文件是否是 NTFS 硬链接(hard link)(罕见,但最古老),则 NTFS junction to a directory ,一个NTFS symlink ,一个NTFS volume mount point ,或any type of NTFS reparse point ,事情变得更加复杂。 [This answer很好地描述了前三个。]

让我们创建一个简单的 NTFS 文件夹来测试:

# Create a test directory and change to it.
New-Item -Path C:\linktest -ItemType Directory | Select-Object -ExpandProperty FullName | Push-Location

# Create an empty file
New-Item -Path .\file1 -ItemType file -Value $null | Out-Null
New-Item -Path .\file2 -ItemType file -Value $null | Out-Null

# Create a directory
New-Item -Path .\dir1 -ItemType Directory | Out-Null

# Create a symlink to the file
New-Item -ItemType SymbolicLink -Path .\sfile1 -Value .\file1 | Out-Null

# Create a symlink to the folder
New-Item -ItemType SymbolicLink -Path .\sdir1 -Value .\dir1 | Out-Null

# Create a hard link to the file
New-Item -ItemType HardLink -Path .\hfile1 -Value .\file1 | Out-Null

# Create a junction  to the folder
New-Item -ItemType Junction -Path .\jdir1 -Value .\dir1 | Out-Null

# View the item properties
Get-ChildItem -Path . | Sort-Object Name | Format-Table -Property Name, PSIsContainer, LinkType, Target, Attributes -AutoSize

您的输出将是:

Name   PSIsContainer LinkType     Target                            Attributes
----   ------------- --------     ------                            ----------
dir1            True              {}                                 Directory
file1          False HardLink     {C:\linktest\hfile1}                 Archive
file2          False              {}                                   Archive
hfile1         False HardLink     {C:\linktest\file1}                  Archive
jdir1           True Junction     {C:\linktest\dir1}   Directory, ReparsePoint
sdir1           True SymbolicLink {C:\linktest\dir1}   Directory, ReparsePoint
sfile1         False SymbolicLink {C:\linktest\file1}    Archive, ReparsePoint

请注意,file1hfile1 都是硬链接(hard link),即使 file1 不是这样创建的。

要清理上述垃圾,请执行以下操作:

Get-ChildItem -Path C:\linktest\ | ForEach-Object { $_.Delete() }

a bug in Remove-Item删除一些容器链接,这会阻止命令删除项目。

一般的解决方案是获取该项目并测试它:

# Get the item. Don't use Get-ChildItem because that will get a directory's contents
$Item = Get-Item -Path $Path

# Is it a container
$Item.PSIsContainer

# Is it a link of some kind?
[System.String]::IsNullOrWhiteSpace($Item.LinkType)
$Item.LinkType -eq 'Junction'

# Is it a Reparse Point?
($Item.Attributes -band [System.IO.FileAttributes]::ReparsePoint) -eq [System.IO.FileAttributes]::ReparsePoint

还有其他几个潜在的属性:

PS> [System.Enum]::GetNames([System.IO.FileAttributes])
ReadOnly
Hidden
System
Directory
Archive
Device
Normal
Temporary
SparseFile
ReparsePoint
Compressed
Offline
NotContentIndexed
Encrypted
IntegrityStream
NoScrubData

请注意Device is documented as reserved for future use 。 Windows 中没有设备文件类型。

对于卷安装点,我不能 100% 确定它们的外观。我知道您可以在 Windows 8.1 及更高版本上使用 Get-Partition 创建它们,然后使用适当的 Add-PartitionAccessPath,但我目前使用的是 Windows 7。恐怕我目前没有办法对此进行测试。

最后,我不知道 Linux 上的 PowerShell Core 6.0 到底如何处理文件类型。

关于shell - 在powershell中检查文件是否可读且正常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48995968/

相关文章:

linux - 在 shell 脚本中使用函数时如何记录压缩的 zip 文件

json - 使用 shell 脚本在特定数组索引后附加 JSON 文件

powershell - 如何在 PowerShell 中写入标准错误?

powershell - 使用 Powershell Match 匹配变量

java - 如何更改默认编译器?

linux - 添加文件夹中所有视频文件的持续时间

powershell - 在 Azure Function 中使用托管标识来访问 Graph API

powershell - 以 powershell 方式连接对象数组的属性

powershell - 动态向Powershell cmdlet添加参数