一直在学习一些PowerShell,我有一个问题,我一直在努力学习如何做数组,并发现有很多方法可以做到这一点。有些阵列是CPU /内存无效的,而其他阵列是无法解决的(所以说互联网)。我相信我正在做的是引用.Net阵列,但却无法完全了解它。
这是我的学习来源:https://ss64.com/ps/syntax-arrays.html
我的两个问题是: 有没有更好的办法? (所以我不要浪费我的时间) 我的语法是否正确?
错误:
Cannot index into a null array.
At C:\Test\custadmin.ps1:54 char:34
+ out-file -filePath $log[0]::$log[ <<<< 1] -encoding 'UTF8' -append -width 200 -inputObject $log[3]
+ CategoryInfo : InvalidOperation: (1:Int32) [], RuntimeException
+ FullyQualifiedErrorId : NullArray
代码:
#Variables
$date = Get-Date
$dateformat = $date.Year+$date.Month+$date.Day
$site = "Example"
$email = New-Object System.Collections.ArrayList
$log = New-Object System.Collections.ArrayList
$schedule = New-Object System.Collections.ArrayList
$error = New-Object System.Collections.ArrayList
#Array Log Variables
$log.Add("\\$site-srv-sbs\Logs\") > $null #path
$log.Add("$dateformat_"+$env:UserName+".txt") > $null #name
$log.Add("This is a report /n/r --------------------- /n/r/n/r Username: "+$env:UserName+" /n/rComputerName: "+$env:computername+" /n/r/n/r") > $null #body
#Log txt file
out-file -filePath $log[0]::$log[1] -encoding 'UTF8' -append -width 200 -inputObject $log[3]
答案 0 :(得分:1)
是的,有更好的方法。 PowerShell一直在幕后使用.Net阵列,所以你真的不需要明确地使用ArrayLists等。
如果您需要PowerShell中的数组,可以通过多种方式创建它们。在PowerShell中,它如此自然,几乎隐藏在你身上。例如:
$array = 1,2,3
或
$files = get-childitem *.log
两者都真正创建数组。不要试图通过尝试将所有变量都放入$ log来开始试图找到数组的应用程序,这是不自然的。创建具有有意义名称的变量,而不是必须记住$ log [3]还没有存储任何数据。
答案 1 :(得分:1)
Burt_Harris' helpful answer包含有关数组和数组使用语义的一般建议。
此时值得重复Burt的建议:使用数组 你的特定用例似乎是错误的;个别变量使解决方案更具可读性和可维护性。
这个答案的其余部分将这个方面放在一边(可能是你的代码的细节是次要的,你的问题是关于一般的数组使用)并且显示如何在PowerShell-idiomatic中使用数组和其他语法功能方式。强>
除非性能至关重要 - 例如在逐渐构建大型数组时 - 使用PowerShell自己的数组(.NET类型为[System.Object[]]
)比处理更简单与[System.Collections.ArrayList]
:
# * Since all elements are known in advance, simply use `,`, the array-constructor
# operator to create your array.
# * Also note that I've embedded the variable references directly
# inside "...", with variable names disambiguated with {...}, where necessary.
# * Finally, /n/r instances have been replaced with `r`n (CRLF) - note that ` (backtick)
# is the escape char. in PowerShell.
$log = "\\$site-srv-sbs\Logs\",
"${dateformat}_${env:UserName}.txt",
"This is a report`r`n---------------------`r`n`r`nUsername: $env:UserName`r`nComputerName: $env:computername`r`n`r`n"
如果效率很重要:
为了有效扩展数组迭代,请使用$arrayList =
[System.Collections.ArrayList]::new()
或其通用的强类型表兄弟;例如,[string]
个实例,$list = [System.Collections.Generic.List[string]]::new()
虽然PowerShell可以方便地让您扩展&#34;一个+=
的数组,每次必须在幕后分配一个全新的数组。
为了有效地存储数组(但在shell环境中很少重要)和/或类型安全访问,请使用$list = [System.Collections.Generic.List[int]]::new()
例如,但请注意,只有值类型(例如[int]
),而不是引用类型(例如[string]
)的存储效率才会提高)。
值类型的另一个有益副作用是元素访问速度稍快。
您$log[0]::$log[1]
的意图似乎只是 连接 $log[0]
和$log[1]
,在这种情况下您有几个选项 - 请注意,$log[2]
而不是$log[3]
必须与-InputObject
一起使用,因为正如Burt所指出的,2
是最后一个元素的索引,而不是{ {1}}:
3
语法错误的原因:
# Use "..."
# Inside "...", anything beyond a simple variable access - such as indexed
# access here - must be enclosed in $(...), the subexpression operator.
Out-File -FilePath "$($log[0])$($log[1])" -encoding UTF8 -append -width 200 -inputObject $log[2]
# Alternative, using an expression:
Out-File -FilePath ($log[0] + $log[1]) -encoding UTF8 -append -width 200 -inputObject $log[2]
# Generally preferable: Using the Join-Path cmdlet
Out-File -FilePath (Join-Path $log[0] $log[1]) -encoding UTF8 -append -width 200 -inputObject $log[2]
是静态解除引用运算符,其目的是提供对.NET类型的静态成员(属性和方法)的访问 - 请参阅Get-Help about_Operators
。
::
的类型为$log[0]
,因此[string]
会查找该类型的静态成员。
由于::
的优先级高于::
,因此请先查看Get-Help about_Operator_Precedence
- []
,然后查找名称为{{1}的静态成员}}
因为成员名称是字符串而$log[0]::$log
是数组,所以$log
被强制转换为字符串,在PowerShell中是以空格分隔的数组元素列表。
显然,类型$log
上不存在这样的静态成员,因此表达式的一部分计算为$log
。
[string]
应用于$null
,这是无效的,并导致您看到错误([0]
)。