问题描述
我正在尝试通过在文件中添加基于递增计数器的前缀来重命名文件,例如:
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
但是所有处理过的文件都是71_
和$count
在$count++
中永不递增,并且文件名是否具有相同的前缀?为什么?
Yet all the files processed are 71_
and $count
in $count++
never increments and the filenames are prefixed the same? Why?
推荐答案
不能仅在脚本块中使用$count++
来直接增加序列号的原因是:
The reason you cannot just use $count++
in your script block in order to increment the sequence number directly is:
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.
- 将此与传递给
Where-Object
和ForEach-Object
的脚本块进行对比,这些脚本块直接在调用者的作用域中运行.
不清楚行为上的差异是否是有意的.
- Contrast this with script blocks passed to
Where-Object
andForEach-Object
, which run directly in the caller's scope.
It is unclear whether that difference in behavior is intentional.
因此,试图修改调用方的变量,而是创建了一个 block -局部变量,该变量在每次迭代中都超出了范围,以便下一次迭代再次进行从调用者的作用域中看到原始值.
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.
- 要了解有关范围和隐式局部变量创建的更多信息,请参见此答案.
一种实用但可能有限制的解决方法是使用范围说明符$script:
-即$script:count
-引用调用方的$count
变量:
A pragmatic, but potentially limiting workaround is to use scope specifier $script:
- i.e., $script:count
- to refer to the caller's $count
variable:
$directory = 'C:\Temp'
[int] $count=71
gci $directory | sort -Property LastWriteTime |
rename-item -newname { '{0}_{1}' -f $script:count++, $_.Name } -whatif
这将起作用:
-
在交互式会话中(在命令提示符下,在全局范围内).
in an interactive session (at the command prompt, in the global scope).
,只要$count
变量在脚本的顶级范围内初始化.
- 也就是说,如果您将代码移动到具有 local-
$count
变量的 function 中,它将不再起作用.
- That is, if you moved your code into a function with a function-local
$count
variable, it would no longer work.
灵活的解决方案需要可靠的 relative 引用 parent 范围:
A flexible solution requires a reliable relative reference to the parent scope:
有两种选择:
- 概念清晰,但冗长且相对较慢,因为必须调用cmdlet:
(Get-Variable -Scope 1 count).Value++
- conceptually clear, but verbose and comparatively slow, due to having to call a 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++
- somewhat obscure, but faster and more concise:
([ref] $count).Value++
gci $directory | sort -Property LastWriteTime |
rename-item -newname { '{0}_{1}' -f ([ref] $count).Value++, $_.Name } -whatif
[ref] $count
实际上与Get-Variable -Scope 1 count
相同(假定在父作用域中设置了$count
变量)
[ref] $count
is effectively the same as Get-Variable -Scope 1 count
(assuming that a $count
variable was set in the parent scope)
注意:从理论上讲,您可以使用$global:count
来初始化和递增 any 范围内的 global 变量,但是考虑到全局变量甚至在脚本执行后仍然存在最后,您还应该预先保存任何先前存在的$global: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.
这篇关于变量上的++运算符未按ScriptBlock中的预期进行更改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!