英文:
Two identical strings are "not equal". Why?
问题
I'm trying to figure out why these two strings are not equal. Is there a better operator I should use?
英文:
Im trying to figure out why these two strings are not equal. Is there a better operator I should use?
$lastupdated = invoke-webrequest -uri $source | Out-String -Stream | Select-String Last-Modified
$storeddate = get-content C:\windows\file.txt
答案1
得分: 1
Sure, here is the translated code snippet:
$lastupdated -ne $storeddayed
True
Indeed means that the values aren't identical even their **basic properties** (display values) appear to be the same.
PowerShell is a [loosely typed programming](https://en.wikipedia.org/wiki/Strong_and_weak_typing) which lets you "conveniently" compare two values of different types. Try this:
$lastupdated.GetType()
$storeddayed.GetType()
I suspect that the `$storeddayed` variable is actually a string as the name implies that it has been stored where it has likely lost its fidelity of the actual [`datetime` structure](https://learn.microsoft.com/dotnet/api/system.datetime) as it has either been [converted automatically](https://learn.microsoft.com/powershell/scripting/lang-spec/chapter-06) or "manually" as you do in your own [answer](https://stackoverflow.com/a/76277291/1701026) with the `ToString()` method.
If you compare two different types of objects, the object on the RHS (right hand side) dictates the conversion for the comparison (this generally counts for any other operator).
This means that you might just convert the right side (or both sides) to a string (using double quotes):
"$lastupdated" -ne "$storeddayed"
Or simply swap the operands in the operation to get what you expected:
$storeddayed -ne $lastupdated
Also note that in case the operands (`$storeddayed` and `$lastupdated`) are *both* of the `datetime` structure, not all detailed [properties](https://learn.microsoft.com/dotnet/api/system.datetime#properties) are displayed by default (think of the timezone information and e.g. the `millisecond` property).
In other words, if you give the commands in one go:
$lastupdated = Get-Date()
$storeddayed = Get-Date()
They might look the same as you display them (as strings) but they actually differ in time:
$lastupdated.Millisecond
$storeddayed.Millisecond
I hope this helps!
英文:
$lastupdated -ne $storeddayed
True
Indeed means that the values aren't identical even their basic properties (display values) appear to be the same.
PowerShell is a loosely typed programming which lets you "convienently" compare two values of a different type. Try this:
$lastupdated.GetType()
$storeddayed.GetType()
I suspect that the $storeddayed
variable is actually a string as the name implies that it has been stored were it is has likely lost its fidelity of the actual datetime
structure as it has either been converted automaticaly or "manually" as you do in your own answer with the ToString()
method.
If you compare two different types the objects. The object at the RHS (right hand side) dictates the conversation for the comparison (this generally counts for any other operator).
This means that you might just convert the right side (or both sides) to a string (using double quotes):
"$lastupdated" -ne "$storeddayed"
Or simply swap the operants in the operation to get what you expected:
$storeddayed -ne $lastupdated
Also note that in case the operants ($storeddayed
and $lastupdated
) are both of the datetime
structure, not all detailed properties are displayed by default (think of the timezone information and e.g. the millisecond
property).
In other words, if you give the commands in one go:
$lastupdated = Get-Date()
$storeddayed = Get-Date()
They might look the same as you display them (as string) but they actually differ in time:
$lastupdated.Millisecond
$storeddayed.Millisecond
答案2
得分: 1
以下是翻译的内容:
根本原因
根据您如何初始化$storeaddate
...
$storeddate = get-content C:\windows\file.txt
...我会假设您的文件只包含一行文本,类似这样...
Last-Modified Web 17, May 2023 23:27:24 GMT
...这使它成为一个[string]
实例。
而$lastupdated
是这样初始化的:
$lastupdated = invoke-webrequest -uri $source | Out-String -Stream | Select-String Last-Modified
这意味着它是一个Microsoft.PowerShell.Commands.MatchInfo
对象,因为这是Select-String
返回的内容。
您可以使用以下命令来检查:
$lastupdated.GetType().FullName
# Microsoft.PowerShell.Commands.MatchInfo
您还可以使用以下命令查看更多详细信息:
$lastupdated | fl *
# IgnoreCase : True
# LineNumber : 1
# Line : Last-Modified Web 17, May 2023 23:27:24 GMT
# Filename : InputStream
# Path : InputStream
# Pattern : Last-Modified
# Context :
# Matches : {0}
$storeddate -ne $lastupdated
始终返回 $true
的原因是因为[string]
和 [matchinfo]
永远不相等。
解决方法
如果您想获得从Select-String
返回的返回值的文本表示(即[string]
),可以执行以下操作:
$lastupdated = invoke-webrequest -uri $source `
| Out-String -Stream `
| Select-String Last-Modified `
| select-object -ExpandProperty "Line"
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - 提取“Line”属性的值
$lastupated
# Last-Modified Web 17, May 2023 23:27:24 GMT
(注意select-object -ExpandProperty "Line"
,它从matchinfo
对象中提取Line
属性的值)
现在,$lastupdated
真的是一个[string]
,而不是一个MatchInfo
,当它们相同时,您应该发现 $storeddate -ne $lastupdated
会正确返回 $false
。
Last-Modified
标头
尽管说了这么多,我猜您实际上真正想要的是从调用invoke-webrequest
获取Last-Modified
响应标头,您可以通过以下方式更轻松地获取它:
$response = invoke-webrequest -uri $source
$lastupdated = $response.Headers["Last-Modified"]
$lastupdated
# Web 17, May 2023 23:27:24 GMT
这不会受到在提取Last-Modified
之前对响应进行脆弱字符串化的影响。
而且,如果您使用Last-Modified
标头来确定资源是否已更新,您可能还可以使用HEAD
方法,以避免下载整个资源内容,因为这正是您首先要避免做的,如果它已经是最新的话:
$response = invoke-webrequest `
-Uri "www.google.com" `
-Method "HEAD" `
-UseBasicParsing
$lastupdated = $response.Headers["Last-Modified"]
$lastupdated
# Web 17, May 2023 23:27:24 GMT
英文:
Root Cause
Based on how you're initialising $storeaddate
...
$storeddate = get-content C:\windows\file.txt
... I'm going to assume your file has just got a single line of text with something like this in it..
Last-Modified Web 17, May 2023 23:27:24 GMT
... which makes it a [string]
instance.
Whereas $lastupdated
is initialised like this:
$lastupdated = invoke-webrequest -uri $source | Out-String -Stream | Select-String Last-Modified
which means it's a Microsoft.PowerShell.Commands.MatchInfo
object because that's what Select-String
returns.
You can check that with this:
$lastupdated.GetType().FullName
# Microsoft.PowerShell.Commands.MatchInfo
and you can see more details with this:
$lastupdated | fl *
# IgnoreCase : True
# LineNumber : 1
# Line : Last-Modified Web 17, May 2023 23:27:24 GMT
# Filename : InputStream
# Path : InputStream
# Pattern : Last-Modified
# Context :
# Matches : {0}
The reason youc $storeddate -ne $lastupdated
always returns $true
is because a [string]
and a [matchinfo]
are never equal.
Workaround
If you want to get a textual (i.e. [string]
) representation of the return value from Select-String
you can do this:
$lastupdated = invoke-webrequest -uri $source `
| Out-String -Stream `
| Select-String Last-Modified `
| select-object -ExpandProperty "Line"
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - extract the "Line" property value
$lastupated
# Last-Modified Web 17, May 2023 23:27:24 GMT
(note the select-object -ExpandProperty "Line"
which extracts the value of the Line
property from the matchinfo
object)
And now $lastupdated
really is a [string]
as opposed to a MatchInfo
and you should find $storeddate -ne $lastupdated
will correctly return $false
when they're the same.
Last-Modified
Header
Having said all of that, I'm going to take a bit of a leap and guess that you're really actually after the Last-Modified
response header from your call to invoke-webrequest
which you can get a lot easier if you do this:
$response = invoke-webrequest -uri $source
$lastupdated = $response.Headers["Last-Modified"]
$lastupdated
# Web 17, May 2023 23:27:24 GMT
which won't be affected by differences in brittle stringifying of the response before you extract the Last-Modified
using select-string
.
And, if you're using the Last-Modified
header to decide whether a resource has been updated, you might as well use the HEAD
method as well to avoid downloading the entire resource content, since that's what you're trying to avoid doing in the first place if it's already up to date:
$response = invoke-webrequest `
-Uri "www.google.com" `
-Method "HEAD" `
-UseBasicParsing
$lastupdated = $response.Headers["Last-Modified"]
$lastupdated
# Web 17, May 2023 23:27:24 GMT
答案3
得分: 0
I added the .ToString() when saving the string to a file and now my operator seems to be working.
$lastupdated.ToString() | out-file c:\windows\file.txt
英文:
I added the .ToString() when saving the string to a file and now my operator seems to be working.
$lastupdated.ToString() | out-file c:\windows\file.txt
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论