运算符未按ScriptBlock中的预期进行更改

运算符未按ScriptBlock中的预期进行更改

本文介绍了变量上的++运算符未按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

但是所有处理过的文件都是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.

  • Contrast this with script blocks passed to Where-Object and ForEach-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中的预期进行更改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-07 04:36