在powershell中检查文件是否可读且规则

在powershell中检查文件是否可读且规则,shell,powershell,powershell-3.0,powershell-4.0,Shell,Powershell,Powershell 3.0,Powershell 4.0,我是powershell的新手,我想检查文件是否可读和正常。在unix中,我们可以使用-f&-r在一行中完成。例如,下面的shell脚本函数接受filename作为参数,并检查文件的可读性和规则性,powershell的等效功能是什么 _ChkRegularFile_R() # checks whether a file is regular and readable { _CRFRfilename=$1 # name of th

我是powershell的新手,我想检查文件是否可读和正常。在unix中,我们可以使用-f&-r在一行中完成。例如,下面的shell脚本函数接受filename作为参数,并检查文件的可读性和规则性,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
}

这不是我经常做的事,但如果记忆有用的话。在*nix中,包含数据的常规文件是目录,
再说一次,在普通的豪华服装下,我不必担心什么

那么您正在测试对象是可写文件(和/或非零)还是目录或二进制文件

所以,在时尚中,在v3之前。。。你这样做

$IsDir = {$_.PsIsContainer}
$IsFile = {!$_.PsIsContainer}

ls D:\Temp | Where $IsDir

    lsectory: D:\Temp


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----         1/4/2018   2:31 PM                ArchiveDestination
d-----         1/4/2018   1:40 PM                ArchiveSource
d-----         1/1/2018   3:34 PM                diff
...    



ls D:\Temp | Where $IsFile

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----         6/7/2017   5:28 PM            512 CombinedSources07Jun2017.txt
-a----        2/24/2018   6:29 PM            115 EmpData.csv
-a----       11/18/2017   6:47 PM          11686 fsoVolume.docx
...
豪华V3和更高。这是本机支持的,例如:

ls -directory
ls -ad
ls -file
ls -af
当然,可以使用if/then或try/catch将上述任何一项设置为仅返回true或false

如果以上所有内容都比您希望的要多键入一些,那么您可以创建自己的函数,并为其指定您选择的任何别名,只要它不是已在使用的别名

请参阅帮助文件

# Get parameters, examples, full and Online help for a cmdlet or function

(Get-Command -Name Get-ChildItem).Parameters
Get-help -Name Get-ChildItem -Examples
Get-help -Name Get-ChildItem -Full
Get-help -Name Get-ChildItem -Online

Get-Help about_*
Get-Help about_Functions
Get-Alias -Definition Get-ChildItem

# Find all cmdlets / functions with a target parameter
Get-Help * -Parameter Append

# All Help topics locations
explorer "$pshome\$($Host.CurrentCulture.Name)"
当然,您也可以检查/修改文件属性。请参阅这篇关于以下主题的文章:

PowerShell中的文件属性

通过PowerShell和DIR命令,轻松使用文件和文件夹属性

因此,您可以这样做,以实现相同的属性检查

Get-ChildItem -Path $FilePath -File -Force | Where {$_.Attributes -notmatch 'ReadOnly'}
或具有别名的函数

Function Test-RegularFile
{
    [CmdletBinding()]
    [Alias('trf')]

    Param
    (
        [string]$FilePath
    )

    try
    {
        Get-ChildItem -Path $FilePath -File -Force `
        | Where {$_.Attributes -notmatch 'ReadOnly'}
        "$FilePath is a regular file" # success: regular file is readable
    }
    catch 
    {
        Write-Warning -Message "$FilePath is not a Regular file."
    }
}

trf -FilePath D:\Temp\fsoVolume.txt
因为你是一个时尚新手,所以在进行转换比较之前,对转换有一个基本的了解是非常重要的。 有关提供学习PowerShell的一些途径的人员,请参阅本文。
要测试文件是否可读,请尝试打开它。如果你得到一个错误,那么它是不可读的。您需要捕获或捕获异常,或者在出现错误时停止(视情况而定)。请记住,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
如果您正在使用
FileInfo
DirectoryInfo
对象(即
Get Item
Get ChildItem
,或表示文件或目录的类似对象的输出),您将拥有
PSIsContainer
属性,该属性将告诉您该项是文件还是目录

这可能涵盖99.999%的病例


但是,如果您需要知道某个文件是否是指向某个文件的NTFS硬链接(很少见,但最旧),则会变得更复杂。[很好地描述了前三项。]

让我们创建一个简单的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
请注意,
file1
hfile1
都是硬链接,即使
file1
不是这样创建的

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

Get-ChildItem -Path C:\linktest\ | ForEach-Object { $_.Delete() }
删除某些容器链接会导致命令无法删除这些项

一般解决方案是获取项目并对其进行测试:

# 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
请注意。Windows中没有设备文件类型

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


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

要测试它是否为常规文件:

Test-Path -PathType Leaf foo.txt
要测试它是否可读,请执行以下操作:

Get-ChildItem foo.txt | ? { $_.Mode -match 'r'}
要测试它是否隐藏,请执行以下操作:

Get-ChildItem -force foo.txt | ? { $_.Mode -match 'h'}

嗯,windows的工作原理与*nix不同。在windows中,文件是常规文件的想法是不存在的。您是在windows或*nix中执行此操作的吗?仅供参考,您的函数可以像
\u ChkRegularFile\u R(){[-f“$1”]&&[-R“$1”];}
那样编写,以澄清:类似POSIX的shell中的文件测试操作符
-f
执行隐式符号链接解析;也就是说,如果参数是一个常规文件,或者如果它是一个符号链接,则返回true,如果它的(最终)目标是一个常规文件,则返回true。基本上,我将shell脚本转换为等效的powershell脚本,因此,这些powershell脚本将仅在Windows@ebgreen中运行,这样您就不必担心它是否是常规文件;我建议在命令中使用
-LiteralPath
(除了
新项
调用,该调用仅支持
-Path
,但具有
-LiteralPath
语义),以免路径被解释为通配符模式(OP的示例不涉及全局搜索)。一个简单但不太明显的方法来获得一个布尔值,指示文件是否是一个链接:<代码> [BoOL] $ item。LinkType < /C> > @ MKLMunt0当<代码> - LiteralPath <代码>是默认参数而不是<> >路径< /代码>时,我将考虑切换。事实上,我的回答是有教育意义的。为了清晰起见,我在回答中指定了参数并避免使用别名
-LiteralPath
被设计为特殊情况,而不是默认情况。您的意思可能是
Get ChildItem foo.txt |?{$\.Mode-notmatch'r'}
r
是只读属性)。但是,这还不足以确定当前用户是否可以读取该文件,因为它的ACL可能会阻止读取。我想知道一个文件是否为常规文件,这个答案恰好显示了最自然的方式,即使它可能没有回答原始问题