powershell - ++ 变量上的运算符未在 ScriptBlock 中按预期更改
问题描述
我正在尝试通过在文件中添加基于递增计数器的前缀来重命名文件,例如:
$directory = 'C:\Temp'
[int] $count=71;
gci $directory | sort -Property LastWriteTime | `
rename-item -newname {"{0}_{1}" -f $count++, $_.Name} -whatif
然而,所有处理的文件都是并且71_
永远不会增加,并且文件名的前缀相同?为什么?$count
$count++
解决方案
您不能只$count++
在脚本块中使用以直接增加序列号的原因是:
延迟绑定脚本块(例如您传递给的
Rename-Item -NewName
脚本块)和计算属性中的脚本块在子作用域中运行。Where-Object
将此与传递给and的脚本块进行对比ForEach-Object
,后者直接在调用者的范围内运行。
尚不清楚这种行为差异是否是故意的。
因此,尝试修改调用者的变量会创建一个在每次迭代中超出范围的块局部变量,以便下一次迭代再次从调用者的范围中看到原始值。
- 要了解有关范围和隐式局部变量创建的更多信息,请参阅此答案。
解决方法
一个务实但可能受到限制的解决方法是使用范围说明符$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
这将起作用:
在交互式会话中(在命令提示符下,在全局范围内)。
在脚本中,只要
$count
变量在脚本的顶级范围内初始化。- 也就是说,如果您将代码移动到具有函数局部变量
$count
的函数中,它将不再起作用。
- 也就是说,如果您将代码移动到具有函数局部变量
一个灵活的解决方案需要对父范围的可靠相对引用:
有两种选择:
- 由于必须调用 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++
gci $directory | sort -Property LastWriteTime |
rename-item -newname { '{0}_{1}' -f ([ref] $count).Value++, $_.Name } -whatif
[ref] $count
实际上与Get-Variable -Scope 1 count
(假设$count
在父范围中设置了一个变量)相同
注意:理论上,您可以在任何$global:count
范围内使用初始化和递增全局变量,但鉴于全局变量即使在脚本执行结束后仍然存在,您还应该事先保存任何预先存在的值,然后再恢复它,这使得方法不切实际。$global:count
推荐阅读
- python-3.x - 气流错误:ValueError:未知语言环境:UTF-8
- perl - 模块 `Regexp::Autoflags` 是否已弃用?
- java - Selenium - 获取列标题下的所有单元格
- amazon-web-services - AWS CodePipeline for Serverless : Integrating with Gitlab
- keycloak - Keycloak中新添加的领域管理员无法登录领域
- javascript - Central - Peripharal / Client - 服务器架构,BLE 通信 Tizen Wearable 与 iOS 不工作
- sas - SAS proc 制表,按特定变量排序
- java - 与 Linux VmRSS 和 Java NativeMemoryTraking (NMT) 的总提交内存的差异
- javascript - 我的代码在某些更改后停止工作
- mongodb - 带有自签名证书的 Mongo URI