[英]++ Operator on Variable Is Not Changing As Expected In ScriptBlock
I am trying to rename files by putting a prefix based on an incrementing counter in the files such as: 我试图通过在文件中添加基于递增计数器的前缀来重命名文件,例如:
$directory = 'C:\Temp'
[int] $count=71;
gci $directory | sort -Property LastWriteTime | `
rename-item -newname {"{0}_{1}" -f $count++, $_.Name} -whatif
Yet all the files processed are 71_
and $count
in $count++
never increments and the filenames are prefixed the same? 但是所有处理过的文件都是$count++
中的71_
和$count
永不递增,并且文件名是否前缀相同? Why? 为什么?
The reason you cannot just use $count++
in your script block in order to increment the sequence number directly is: 您不能仅在脚本块中使用$count++
来直接增加序列号的原因是:
Delay-bind script blocks - such as the one you passed to Rename-Item -NewName
- and script blocks in calculated properties run in a child scope . 延迟绑定脚本块 (例如您传递给Rename-Item -NewName
脚本块)和计算所得属性中的脚本块在子作用域中运行。
Where-Object
and ForEach-Object
, which run directly in the caller's scope. 与传递给Where-Object
和ForEach-Object
脚本块进行对比,后者直接在调用者的作用域中运行。 Therefore, attempting to modify the caller's variables instead creates a block -local variable that goes out of scope in every iteration , so that the next iteration again sees the original value from the caller's scope. 因此, 尝试修改调用者的变量会创建一个块局部变量,该变量在每次迭代中都超出范围 ,以便下一次迭代再次从调用者的范围中看到原始值。
A pragmatic, but potentially limiting workaround is to use scope specifier $script:
- ie, $script:count
- to refer to the caller's $count
variable: 一个实用的但可能有限制的解决方法是使用范围说明符$script:
-即$script:count
引用调用者的$count
变量:
$directory = 'C:\Temp'
[int] $count=71
gci $directory | sort -Property LastWriteTime |
rename-item -newname { '{0}_{1}' -f $script:count++, $_.Name } -whatif
This will work: 这将起作用:
in an interactive session (at the command prompt, in the global scope). 在交互式会话中(在命令提示符下,在全局范围内)。
in a script, as long as the $count
variable was initialized in the script's top-level scope . 在脚本中,只要在脚本的顶级范围内初始化$count
变量即可。
$count
variable, it would no longer work. 也就是说,如果你有一个函数本地移动你的代码到一个函数 $count
变量,它不再工作。 A flexible solution requires a reliable relative reference to the parent scope : 灵活的解决方案需要对父范围的可靠的相对引用 :
There are two choices: 有两种选择:
(Get-Variable -Scope 1 count).Value++
由于必须调用cmdlet,因此在概念上清晰,但冗长且相对较慢 : (Get-Variable -Scope 1 count).Value++
gci $directory | sort -Property LastWriteTime |
rename-item -newname { '{0}_{1}' -f (Get-Variable -Scope 1 count).Value++, $_.Name } -whatif
([ref] $count).Value++
有点晦涩,但更快,更简洁 : ([ref] $count).Value++
gci $directory | sort -Property LastWriteTime |
rename-item -newname { '{0}_{1}' -f ([ref] $count).Value++, $_.Name } -whatif
[ref] $count
is effectively the same as Get-Variable -Scope 1 count
(assuming that a $count
variable was set in the parent scope) [ref] $count
实际上与Get-Variable -Scope 1 count
(假设在父范围中设置了$count
变量)
Note: In theory, you could use $global:count
to both initialize and increment a global variable in any scope, but given that global variables linger even after script execution ends, you should then also save any preexisting $global:count
value beforehand, and restore it afterwards, which makes this approach impractical. 注意:从理论上讲,您可以使用$global:count
在任何范围内初始化和递增全局变量,但是鉴于全局变量即使在脚本执行结束后仍然存在,您还应该事先保存任何先前存在的$global:count
值,并随后将其还原,这使该方法不切实际。
@mklement0's answer is correct, but I think this is much easier to understand than dealing with references: @ mklement0的答案是正确的,但是我认为这比处理引用更容易理解:
Get-ChildItem $directory |
Sort-Object -Property LastWriteTime |
ForEach-Object {
$NewName = "{0}_{1}" -f $count++, $_.Name
Rename-Item $_ -NewName $NewName -WhatIf
}
Wow, this is coming up a lot lately. 哇,最近出现了很多。 Here's my current favorite foreach multi scriptblock alternative. 这是我当前最喜欢的foreach多脚本块替代方案。 gci with a wildcard gives a full path to $_ later. 带通配符的gci稍后提供了$ _的完整路径。 You don't need the backtick continuation character after a pipe or an operator. 在管道或运算符之后,您不需要反引号连续字符。
$directory = 'c:\temp'
gci $directory\* | sort LastWriteTime |
foreach { $count = 71 } { rename-item $_ -newname ("{0}_{1}" -f
$count++, $_.Name) -whatif } { 'done' }
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.