Пакетное изменение каталога с помощью Powershell

#powershell

#powershell

Вопрос:

Мне нужно обновить каталог во многих текстовых файлах

 Input files:
1.txt
using c:data1.dta
its own data

2.txt
using c:data2.dta
its own data

3.txt
using c:data3.dta
its own data

Expected Output files:
1.txt
using C:DataSubfile1.dta
its own data

2.txt
using C:DataSubfile2.dta
its own data

3.txt
using C:DataSubfile3.dta
its own data
  

Я пробовал -replace, но результаты странные: либо все файлы имеют одинаковый результат, либо имеют все новые каталоги (см. ниже)

Я хочу обновить старый путь до нового пути во всех файлах. Код выглядит следующим образом:

 $pathway='C:DataSubfile*.txt'
$oldpath='c:\data\'
$newpath='C:DataSubfile'
$content=Get-Content -path $pathway
  

Способ 1:

 $newline=((Get-Content -path $pathway -TotalCount 1) -replace $oldpath,$newpath)
$content[0]= $newline

This method will include all updated directories in every file:
Wrong output:
1.txt
using C:DataSubfile1.txt
using C:DataSubfile2.txt
using C:DataSubfile3.txt
its own data

2.txt
using C:DataSubfile1.txt
using C:DataSubfile2.txt
using C:DataSubfile3.txt
its own data
  

Способ 2:

 $content[0]=$content[0]-replace $oldpath,$newpath

This method will cause all file has the same new directory:
Wrong output:
1.txt
using C:DataSubfile1.txt 
its own data

2.txt
using C:DataSubfile1.txt 
its own data

3.txt
using C:DataSubfile1.txt 
its own data

$content | Set-Content -Path $pathway
  

Может ли кто-нибудь помочь мне с этим? Я хочу, чтобы у каждого файла был соответствующий новый каталог. Для 1.txt Я хочу C:DataSubfile1.txt , для 2.txt Я хочу C:DataSubfile2.txt и т.д.

Большое спасибо!

Комментарии:

1. Мне не ясно, какие данные у вас есть и какие данные вы хотите. Вы говорите: » Я хочу, чтобы у каждого файла был соответствующий новый каталог. Для 1.txt Я хочу C:DataSubfile1.txt , для 2.txt Я хочу C:DataSubfile2.txt и т.д. » — но у них нет соответствующего нового каталога, у них тот же каталог. Можете ли вы отредактировать в своем вопросе пример того, как файл данных выглядит раньше, и как вы хотите, чтобы он выглядел впоследствии?

2. пожалуйста, добавьте один [или три] примера входных файлов и укажите, каким вы хотите, чтобы каждый из них был после замены.

3. Спасибо @TessellatingHeckler, я обновил свой вопрос, чтобы прояснить их! На самом деле, я хочу обновить один и тот же каталог для всех файлов вместо назначения разных новых каталогов для каждого из них.

4. Спасибо @Lee_Dailey, я обновил свой вопрос, чтобы прояснить их! На самом деле, я хочу обновить один и тот же каталог для всех файлов вместо назначения разных новых каталогов для каждого из них.

5. @northernaland — это делает вещи немного более понятными — спасибо! [ усмешка ]

Ответ №1:

Мне немного неясно, каким вы хотите видеть конечное содержимое. Это using C:DataSubfile1.txt или using C:DataSubfile1.dta ? Я думаю, вы просите о следующем, но если нет, дайте мне знать. Вы можете столкнуться с проблемами скорости / производительности в зависимости от размера ваших файлов.

Если это ваши входные файлы с их содержимым:

 C:dataSubfile1.txt
  using c:data1.dta
  its own data...

C:dataSubfile2.txt
  using c:data2.dta
  its own data...

C:dataSubfile3.txt
  using c:data3.dta
  its own data...
  

тогда это:

 Get-ChildItem c:dataSubfile*.txt | Foreach-Object{
    #Read in all content lines and replace c:data with c:datasubfile
    $content = Get-Content $_.FullName | %{$_ -replace 'c:\Data\', 'c:DataSubfile' }
    #write the new data to file
    $content | Set-Content $_.FullName
}
  

Это приводит к следующему:

 C:dataSubfile1.txt
  using c:DataSubfile1.dta
  its own data...

C:dataSubfile2.txt
  using c:DataSubfile2.dta
  its own data...

C:dataSubfile3.txt
  using c:DataSubfile3.dta
  its own data...
  

Комментарии:

1. Большое спасибо! Этот скрипт больше всего подходит для начинающих вроде меня!

Ответ №2:

С помощью поиска вы можете точно определить, куда вставлять текст, не повторяя шаблон поиска.

 foreach ($File in Get-ChildItem 'C:DataSubfile*.txt'){
    (Get-Content $File -raw) -replace "(?<=C:\data\)(?=d.dta)","Subfile" |
     Set-Content $File
}
  
  • "(?<=C:\data\) является положительным утверждением о нулевой длине,
  • (?=d.dta) является положительным утверждением о нулевой длине,
  • заменяющий текст вставляется между этими двумя.
  • это более безопасно, чем другие подходы, поскольку его можно повторить без повторной вставки Subfile .

Комментарии:

1. Это гораздо лучшее решение для регулярных выражений, чем мое. Мне любопытно, каково влияние на производительность lookbehind / ahead, особенно с большими файлами?

2. @StephenP Я думаю, что есть штраф, не уверен в масштабе. Я протестирую это, если у меня когда-нибудь появится свободное время — 😉

Ответ №3:

вот способ выполнить эту работу. [усмешка] что он делает…

  • между #region/#endregion маркерами просто для того, чтобы заставить файлы работать с
  • считывает список файлов
  • выполняет итерацию по этому списку
  • загружает содержимое каждого из них
  • заменяет старый каталог на новый
  • наконец, записывается новое содержимое

вот код…

 #region - Make files to work with
$Null = New-Item -Path "$env:TEMPTestFiles" -ItemType Directory -ErrorAction SilentlyContinue

$1stFileName = "$env:TEMPTestFiles1.txt"
$1stFileContent = @'
using c:data1.dta
its own data
'@ -split [System.Environment]::NewLine |
    Set-Content -LiteralPath $1stFileName

$2ndFileName = "$env:TEMPTestFiles2.txt"
$2ndFileContent = @'
using c:data2.dta
its own data
'@ -split [System.Environment]::NewLine |
    Set-Content -LiteralPath $2ndFileName

$3rdFileName = "$env:TEMPTestFiles3.txt"
@'
using c:data3.dta
its own data
'@ -split [System.Environment]::NewLine |
    Set-Content -LiteralPath $3rdFileName
#endregion - Make files to work with

$OldDir = 'c:data'
$NewDir = 'c:dataSubDir'

$SourceDir = "$env:TEMPTestFiles"

$FileList = Get-ChildItem -LiteralPath $SourceDir -Filter '*.txt' -File

foreach ($FL_Item in $FileList)
    {
    $NewContent = Get-Content -LiteralPath $FL_Item.FullName |
        ForEach-Object {
            $_.Replace($OldDir, $NewDir)
            }
    $NewContent |
        Set-Content -LiteralPath $FL_Item.FullName
    }
  

содержимое файла 1.txt до и после запуска скрипта…

 # before ...
using c:data1.dta
its own data    

# after ...
using c:dataSubDir1.dta
its own data