【问题标题】:Powershell: Replace strings in all .ini files recursivelyPowershell:递归替换所有.ini文件中的字符串
【发布时间】:2018-12-13 12:54:56
【问题描述】:

我一直想要一个易于使用的脚本,它可以让我在一段时间内替换多个文件中的多个字符串。到目前为止,我已经得到了这个代码:

$replacements = @{
'bCompressDiffuseLocalPlayerCharacterTextures=True' = 'bCompressDiffuseLocalPlayerCharacterTextures=False'
'bCompressDiffuseLocalPlayerVehicleTextures=True'   = 'bCompressDiffuseLocalPlayerVehicleTextures=False'
'bCompressDiffuseOtherPlayerCharacterTextures=True' = 'bCompressDiffuseOtherPlayerCharacterTextures=False'
'bCompressDiffuseOtherPlayerVehicleTextures=True'   = 'bCompressDiffuseOtherPlayerVehicleTextures=False'
'bCompressNormalTextures=True'                      = 'bCompressNormalTextures=False'
'bDisablePhysXHardwareSupport=True'                 = 'bDisablePhysXHardwareSupport=False'
'bEnableMouseSmoothing=True'                        = 'bEnableMouseSmoothing=False'
'bInitializeShadersOnDemand=True'                   = 'bInitializeShadersOnDemand=False'
'MaxChannels=32'                                    = 'MaxChannels=64'
'MotionBlur=True'                                   = 'MotionBlur=False'
'm_bCalculateOnServer=True'                         = 'm_bCalculateOnServer=False'
'OneFrameThreadLag=True'                            = 'OneFrameThreadLag=False'
'PoolSize=140'                                      = 'PoolSize=1024'
'UseMinimalNVIDIADriverShaderOptimization=True'     = 'UseMinimalNVIDIADriverShaderOptimization=False'
'UseTextureFileCache=False'                         = 'UseTextureFileCache=True'
}

function Update-FileContent {

[cmdletbinding()]
param(
    [Parameter(ValueFromPipeline=$true,
                ValueFromPipelineByPropertyName=$true,
                Mandatory=$true,
                Position=0)]
    [Alias('PsPath')]
    $Path
)

$lines = Get-Content $Path
$lines | ForEach-Object {

    foreach($rep in $replacements.Keys)
    {
        $_ = $_ -replace $rep, $replacements[$rep]
    }

    $_
} | Set-Content $Path
}

Get-ChildItem -Recurse *.ini | Update-FileContent

只有在文件深度为 1 个目录时才有效。

【问题讨论】:

  • 您希望它在管道中工作吗?那么您需要将process 块添加到您的cmdlet。否则它只适用于管道中的第一项。
  • It works but only if a file is 1 directory deep. 这是否意味着它没有找到其他 ini 文件,或者是否意味着如果有更多目录级别,脚本根本不起作用?你试过什么了?如果你运行gci -Recurse *.ini | Write-Host 会发生什么?您是否尝试过更改函数的绑定并使用“更深”的 INI 文件的路径调用它?
  • 好点,@Matt,虽然它是管道中唯一处理的 last 对象,因为缺少 process 块是隐含的 @987654326 @块。

标签: powershell


【解决方案1】:

我会这样做:

$replacements = @{
    'bCompressDiffuseLocalPlayerCharacterTextures=True' = 'bCompressDiffuseLocalPlayerCharacterTextures=False'
    'bCompressDiffuseLocalPlayerVehicleTextures=True'   = 'bCompressDiffuseLocalPlayerVehicleTextures=False'
    'bCompressDiffuseOtherPlayerCharacterTextures=True' = 'bCompressDiffuseOtherPlayerCharacterTextures=False'
    'bCompressDiffuseOtherPlayerVehicleTextures=True'   = 'bCompressDiffuseOtherPlayerVehicleTextures=False'
    'bCompressNormalTextures=True'                      = 'bCompressNormalTextures=False'
    'bDisablePhysXHardwareSupport=True'                 = 'bDisablePhysXHardwareSupport=False'
    'bEnableMouseSmoothing=True'                        = 'bEnableMouseSmoothing=False'
    'bInitializeShadersOnDemand=True'                   = 'bInitializeShadersOnDemand=False'
    'MaxChannels=32'                                    = 'MaxChannels=64'
    'MotionBlur=True'                                   = 'MotionBlur=False'
    'm_bCalculateOnServer=True'                         = 'm_bCalculateOnServer=False'
    'OneFrameThreadLag=True'                            = 'OneFrameThreadLag=False'
    'PoolSize=140'                                      = 'PoolSize=1024'
    'UseMinimalNVIDIADriverShaderOptimization=True'     = 'UseMinimalNVIDIADriverShaderOptimization=False'
    'UseTextureFileCache=False'                         = 'UseTextureFileCache=True'
}

function Update-FileContent {
    [cmdletbinding()]
    param(
        [Parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Mandatory=$true, Position=0)]
        [Alias('PsPath')]
        $Path
    )

    # read the ini file in as one single string
    $content = Get-Content $Path -Raw
    # copy that string so we can compare at the end of the loop if anything has changed at all
    $newContent = $content
    foreach($rep in $replacements.Keys) {
        $newContent = $newContent -replace $rep, $replacements[$rep]
    }
    # only replace the contents of the ini file if changes are made
    if ($newContent -ne $content) {
        Write-Host "Replacing content of file '$Path'"
        Set-Content $Path -Value $content
    }
}

$rootPath = '<PATH OF THE ROOTFOLDER TO RECURSE WHERE THE INI FILES ARE LOCATED>'
Get-ChildItem -Path $rootPath -Filter '*.ini' -Recurse | ForEach-Object { Update-FileContent $_.FullName }

【讨论】:

  • 在执行时是否需要手动指定而不是基于脚本的位置?
  • @Triksterism 我建议总是给它一个完整的路径。如果不这样做,则使用当前工作目录 ($pwd)。如果您希望它成为脚本本身运行的路径,请查看$PSScriptRoot
  • Theo,我建议将 process 块添加到 Update-FileContent,正如 Matt 最初建议的那样,因此您不需要 ForEach-Object 解决方法。
猜你喜欢
  • 2023-03-04
  • 2018-12-29
  • 1970-01-01
  • 2019-01-03
  • 1970-01-01
  • 2017-04-24
  • 2011-09-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多