изменить файл .txt и сохранить его с помощью PowerShell

Вопрос задан: 8 месяцев назад Последняя активность: 8 месяцев назад
up 0 down

Я делаю классическую функцию поиска и замены в некоторых файлах .txt с powershell. Как я могу "сохранить" файл в конце? Я пытался с | Set-Content, но ничего не происходит. Может быть, мне нужно сначала добавить контент?

#Find what?
$optionBuilderStringToFind = "optionsBuilder.UseSqlServer"
$findUsingKeywordString = "using Microsoft."

#Replace with
$namespaceAdd = "using Microsoft.Extensions.Configuration;"
$optionBuilderConfigurable ="optionsBuilder.UseSqlServer(_configuration.GetConnectionString(`"Database`") 
 );"

gc -Path .\APSContext.cs | % { 
if ($_ -match "using System;") {
    $_ = $_ + "`n" + $namespaceAdd
    #write-host $_
}
if ($_ -match "optionsBuilder.UseSqlServer") {
    $_ = $optionBuilderConfigurable
    #write-host $_
}
} | Set-Content -Path .\test.cs

Обновление: вот testFile, где я хочу изменить его. Содержание файла не важно. Я хочу добавить еще одну ссылку, как "использование Something.Something" и в середине файла, чтобы заменить "optionsBuilder.UseSqlServer("dfjidfjljfiejf88");" с "optionsBuilder.UseSqlServer("_configtest");":

using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;

namespace SRC.APS.Model.APSDB
{
public partial class APSContext : DbContext
{
    public APSContext()
    {
    }

    public APSContext(DbContextOptions<APSContext> options)
        : base(options)
       protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (!optionsBuilder.IsConfigured)
        {

            optionsBuilder.UseSqlServer("dfjidfjljfiejf88");
        }
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.HasAnnotation("ProductVersion", "2.2.0-rtm-35687");

    }

Может быть, мне нужно использовать Out-String вместо этого?

2 ответа

up 1 down accepted

Любой блок скриптов в Powershell может создавать значения. Это сделано, не сохраняя значение в переменной:

  • { $foo = 3 } ничего не производит
  • { 3 } производит целое число 3.

Таким же образом

  • ForEach-Object { $_ = "something" } ничего не производит
  • ForEach-Object { $_ = "something"; $_ } производит строку "something"

Ваше тело цикла ничего не выводит, это как верхний пример выше. Следовательно, Set-Content не имеет никакого отношения. Измените блок, чтобы фактически вернуть измененное значение $_:

$replacements = @(
    @{regex='using (System|Potentially|Others);'; replacement='using Microsoft.$1;' }
    @{regex='optionsBuilder\.UseSqlServer\("[^"]*"\)'; replacement='optionsBuilder.UseSqlServer("Database")' }
    # more search/replace pairs
)

Get-Content .\APSContext.cs -Encoding UTF8 | ForEach-Object {
    foreach ($item in $replacements) {
        $_ = $_ -replace $item.regex, $item.replacement
    }
    $_   # <--- this is what produces the line
} | Set-Content -Path .\test.cs -Encoding UTF8

При этом никогда не загружайте и не сохраняйте текстовые файлы без указания их кодировки. Для файлов исходного кода C# я думаю, что по умолчанию используется UTF-8.

И, как говорится, модификация исходного кода с помощью регулярных выражений не очень хорошая вещь. Если это разовое, хорошо. Если вы планируете делать это регулярно, вы делаете что-то не так. Работайте с конфигурационными файлами или переменными среды вместо того, чтобы хранить в своем коде буквальные значения, которые подвержены регулярным изменениям.

up 0 down

как я уже упоминал - и, как указывал Томалак, - ваша ошибка с текущим объектом конвейера является источником сбоя. [grin] этот код исправляет логическую ошибку в вашем каскаде IF [что может быть лучше сделано с помощью switch блок], удаляет неразумных $_ возиться, а затем гарантирует, что всегда есть какой-то вывод.

# fake reading in a text file
#    in real life, use Get-Content
$InStuff = @'
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;

namespace SRC.APS.Model.APSDB
{
public partial class APSContext : DbContext
{
    public APSContext()
    {
    }

    public APSContext(DbContextOptions<APSContext> options)
        : base(options)
       protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (!optionsBuilder.IsConfigured)
        {

            optionsBuilder.UseSqlServer("dfjidfjljfiejf88");
        }
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.HasAnnotation("ProductVersion", "2.2.0-rtm-35687");

    }
'@ -split [environment]::NewLine

#Find what?
$optionBuilderStringToFind = "optionsBuilder.UseSqlServer"
$findUsingKeywordString = "using Microsoft."

#Replace with
$namespaceAdd = 'using Microsoft.Extensions.Configuration;'
$optionBuilderConfigurable ='optionsBuilder.UseSqlServer(_configuration.GetConnectionString("Database"));'

$InStuff | ForEach-Object { 
    if ($_ -match "using System;")
        {
        $_ + "`n" + $namespaceAdd
        #write-host $_
        }
        elseif ($_ -match "optionsBuilder.UseSqlServer")
        {
        $optionBuilderConfigurable
        #write-host $_
        }
        else
        {
        $_
        }
    }

выход...

using System;
using Microsoft.Extensions.Configuration;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;

namespace SRC.APS.Model.APSDB
{
public partial class APSContext : DbContext
{
    public APSContext()
    {
    }

    public APSContext(DbContextOptions<APSContext> options)
        : base(options)
       protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (!optionsBuilder.IsConfigured)
        {

optionsBuilder.UseSqlServer(_configuration.GetConnectionString("Database"));
        }
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.HasAnnotation("ProductVersion", "2.2.0-rtm-35687");

    }