#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