পাওয়ারশেল ব্যবহার করে, আমি [MYID]
একটি প্রদত্ত ফাইলের সাথে সমস্ত সঠিক উপস্থিতি প্রতিস্থাপন করতে চাই MyValue
। এটি করার সহজতম উপায় কী?
পাওয়ারশেল ব্যবহার করে, আমি [MYID]
একটি প্রদত্ত ফাইলের সাথে সমস্ত সঠিক উপস্থিতি প্রতিস্থাপন করতে চাই MyValue
। এটি করার সহজতম উপায় কী?
উত্তর:
(ভি 3 সংস্করণ) ব্যবহার করুন:
(Get-Content c:\temp\test.txt).replace('[MYID]', 'MyValue') | Set-Content c:\temp\test.txt
অথবা ভি 2 এর জন্য:
(Get-Content c:\temp\test.txt) -replace '\[MYID\]', 'MyValue' | Set-Content c:\temp\test.txt
(Get-Content file.txt) |
Foreach-Object {$_ -replace '\[MYID\]','MyValue'} |
Out-File file.txt
আশেপাশে প্রথম বন্ধনী (Get-Content file.txt)
আবশ্যক:
প্রথম বন্ধনী ছাড়া সামগ্রীটি একবারে এক লাইনে পড়া হয় এবং পাইপলাইনটি প্রবাহিত না হওয়া অবধি প্রবাহিত হয় যতক্ষণ না এটি ফাইল বা সেট-সামগ্রীতে পৌঁছে যায়, যা একই ফাইলটিতে লেখার চেষ্টা করে তবে এটি ইতিমধ্যে গেট-কনটেন্ট দ্বারা খোলা থাকে এবং আপনি পান একটি ভুল. প্রথম বন্ধনী কন্টেন্ট রিডিংয়ের ক্রিয়াকলাপ একবার (খোলা, পড়ুন এবং বন্ধ করুন) সম্পাদন করে। তারপরে সমস্ত লাইনগুলি পড়ার পরে, সেগুলি একবারে একবারে পাইপ দেওয়া হয় এবং পাইপলাইনে শেষ কমান্ডে পৌঁছলে সেগুলি ফাইলে লেখা যায়। এটি $ সামগ্রী = সামগ্রী হিসাবে একই; $ সামগ্রী | কোথায় ...
Set-Content
পরিবর্তে ব্যবহার করে Out-File
একটি সতর্কতা পান যেমন "প্রক্রিয়াটি '123.csv' ফাইলটি অ্যাক্সেস করতে পারে না কারণ এটি অন্য প্রক্রিয়া দ্বারা ব্যবহৃত হচ্ছে।" ।
Get-Content
প্রথম বন্ধনী মধ্যে এটি কাজ করে। আপনার উত্তরটিতে ব্যাখ্যা করতে পারেন কেন প্রথম বন্ধনী প্রয়োজনীয়? আমি এখনও প্রতিস্থাপন করবে Out-File
সঙ্গে Set-Content
কারণ এটি নিরাপদ; এটি যদি আপনি প্রথম বন্ধনী ভুলে যান তবে লক্ষ্য ফাইলটি মুছে ফেলার হাত থেকে রক্ষা করে।
Set-Content
পরিবর্তে ব্যবহার Out-File
করা আরও ভাল এবং নিরাপদ সমাধান। দুঃখিত ডাউন ডাউন করতে হবে।
নীচের উদাহরণে দেখা হিসাবে আমি .NET এর ফাইল-শ্রেণি এবং এর স্থির পদ্ধতিগুলি ব্যবহার করতে পছন্দ করি।
$content = [System.IO.File]::ReadAllText("c:\bla.txt").Replace("[MYID]","MyValue")
[System.IO.File]::WriteAllText("c:\bla.txt", $content)
এতে গেট-কনটেন্টের মতো স্ট্রিং-অ্যারের পরিবর্তে একটি একক স্ট্রিংয়ের সাথে কাজ করার সুবিধা রয়েছে । পদ্ধতিগুলি আপনাকে বেশিরভাগ সময় যত্ন না নিয়েই ফাইলের এনকোডিং (ইউটিএফ -8 বিওএম , ইত্যাদি) যত্ন করে।
এছাড়াও পদ্ধতিগুলি গেট-কনটেন্ট ব্যবহার করে অ্যালগরিদমের বিপরীতে লাইন এন্ডিংগুলিকে (ইউনিক্স লাইন এন্ডিংগুলি ব্যবহার করা হতে পারে) বিভ্রান্ত করে না এবং সেট-সামগ্রীতে পাইপিং করে ।
আমার জন্য তাই: কয়েক বছরের কম জিনিস যা ভেঙে যেতে পারে।
.NET ক্লাসগুলি ব্যবহার করার সময় একটি সামান্য জ্ঞাত জিনিসটি হ'ল আপনি পাওয়ারশেল উইন্ডোতে "[System.IO.File] ::" টাইপ করার পরে আপনি Tabসেখানকার পদ্ধতিগুলি সরাতে কী টিপতে পারেন ।
[System.IO.File] | gm
C:\Windows\System32\WindowsPowerShell\v1.0
?
উপরের একটিটি কেবল "একটি ফাইল" এর জন্য চালিত হয় তবে আপনি এটি আপনার ফোল্ডারের মধ্যে একাধিক ফাইলের জন্য চালাতে পারেন:
Get-ChildItem 'C:yourfile*.xml' -Recurse | ForEach {
(Get-Content $_ | ForEach { $_ -replace '[MYID]', 'MyValue' }) |
Set-Content $_
}
foreach
আপনি এটি করতে পারেনGet-ChildItem 'C:\folder\file*.xml' -Recurse | ForEach { (Get-Content $_).Replace('[MYID]', 'MyValue') | Set-Content $_ }
foreach
, কারণ গেট-কন্টেন্ট এমন কিছু করে যা আপনি প্রত্যাশা করতে পারেন না ... এটি স্ট্রিংগুলির একটি অ্যারে প্রদান করে, যেখানে প্রতিটি স্ট্রিং ফাইলের একটি লাইন। আপনি যদি কোনও চলমান স্ক্রিপ্টের চেয়ে পৃথক স্থানে থাকা কোনও ডিরেক্টরি (এবং উপ ডিরেক্টরি) দিয়ে লুপিং করেন তবে আপনি এর মতো কিছু চাইবেন: Get-ChildItem $Directory -File -Recurse | ForEach { (Get-Content $_.FullName) | ForEach { $_ -replace '[MYID]', 'MyValue' } | Set-Content $_.FullName }
যেখানে $Directory
ফাইলগুলি সংশোধন করতে চান সেই ডিরেক্টরিটি কোথায় ।
এটি আমি ব্যবহার করি তবে এটি বড় টেক্সট ফাইলগুলিতে ধীর হয়।
get-content $pathToFile | % { $_ -replace $stringToReplace, $replaceWith } | set-content $pathToFile
আপনি যদি বড় টেক্সট ফাইলগুলিতে স্ট্রিং প্রতিস্থাপন করতে যাচ্ছেন এবং গতি একটি উদ্বেগজনক বিষয়, System.IO.StreamReader এবং System.IO.StreamWriter ব্যবহার করে দেখুন ।
try
{
$reader = [System.IO.StreamReader] $pathToFile
$data = $reader.ReadToEnd()
$reader.close()
}
finally
{
if ($reader -ne $null)
{
$reader.dispose()
}
}
$data = $data -replace $stringToReplace, $replaceWith
try
{
$writer = [System.IO.StreamWriter] $pathToFile
$writer.write($data)
$writer.close()
}
finally
{
if ($writer -ne $null)
{
$writer.dispose()
}
}
(উপরের কোডটি পরীক্ষা করা হয়নি))
ডকুমেন্টে পাঠ্য প্রতিস্থাপনের জন্য স্ট্রিমরিডার এবং স্ট্রিমউইটার সম্ভবত ব্যবহার করার আরও একটি দুর্দান্ত উপায় আছে তবে এটি আপনাকে একটি ভাল সূচনা পয়েন্ট দেয়।
পাইটের উইন্ডোজ পাওয়ারশেল ইন অ্যাকশন থেকে এটি করার জন্য আমি কিছুটা পরিচিত তবে আশ্চর্যরকম দুর্দান্ত উপায় পেয়েছি । আপনি ভেরিয়েবলের মতো ফাইলগুলি রেফারেন্স করতে পারেন, similar env: পাথের মতো, তবে আপনার কোঁকড়া ধনুর্বন্ধনী যোগ করতে হবে।
${c:file.txt} = ${c:file.txt} -replace 'oldvalue','newvalue'
$myFile
?
$a = 'file.txt'; invoke-expression "`${c:$a} = `${c:$a} -replace 'oldvalue','newvalue'"
যদি আপনার একাধিক ফাইলে স্ট্রিংগুলি প্রতিস্থাপন করতে হয়:
এটি লক্ষ করা উচিত যে এখানে পোস্ট করা বিভিন্ন পদ্ধতিগুলি সম্পূর্ণ হতে সময়টি বিবেচনা করে বুনোভাবে আলাদা হতে পারে। আমার জন্য, আমার নিয়মিত ছোট ছোট ফাইল থাকে। সর্বাধিক পারফরম্যান্ট কী তা পরীক্ষা করতে, আমি 40,693 পৃথক ফাইলে এক্সএমএলের 5.52 জিবি (5,933,604,999 বাইট) বের করেছি এবং আমি এখানে যে উত্তর পেয়েছি তার মধ্যে তিনটি পেয়েছি:
## 5.52 GB (5,933,604,999 bytes) of XML files (40,693 files)
#### Test 1 - Plain Replace
$start = get-date
$xmls = (Get-ChildItem -Path "I:\TestseT\All_XML" -Recurse -Filter *.xml).FullName
foreach ($xml in $xmls)
{
(Get-Content $xml).replace("'", " ") | Set-Content $xml
}
$end = get-date
NEW-TIMESPAN –Start $Start –End $End
<#
TotalMinutes: 103.725113128333
#>
#### Test 2 - Replace with -Raw
$start = get-date
$xmls = (Get-ChildItem -Path "I:\TestseT\All_XML" -Recurse -Filter *.xml).FullName
foreach ($xml in $xmls)
{
(Get-Content $xml -Raw).replace("'", " ") | Set-Content $xml
}
$end = get-date
NEW-TIMESPAN –Start $Start –End $End
<#
TotalMinutes: 10.1600227983333
#>
#### Test 3 - .NET, System.IO
$start = get-date
$xmls = (Get-ChildItem -Path "I:\TestseT\All_XML" -Recurse -Filter *.xml).FullName
foreach ($xml in $xmls)
{
$txt = [System.IO.File]::ReadAllText("$xml").Replace("'"," ")
[System.IO.File]::WriteAllText("$xml", $txt)
}
$end = get-date
NEW-TIMESPAN –Start $Start –End $End
<#
TotalMinutes: 5.83619516833333
#>
ক্রেডিট @ রোমিনেটর 700
আমি এটিকে একটি ফাংশনে আবৃত করেছি (কারণ আপনি এটি আবার ব্যবহার করতে চাইতে পারেন)
function Replace-AllStringsInFile($SearchString,$ReplaceString,$FullPathToFile)
{
$content = [System.IO.File]::ReadAllText("$FullPathToFile").Replace("$SearchString","$ReplaceString")
[System.IO.File]::WriteAllText("$FullPathToFile", $content)
}
দ্রষ্টব্য: এটি কেস সংবেদনশীল নয় !!!!!
পোস্টটি দেখুন: স্ট্রিং। প্রতিস্থাপনের ক্ষেত্রে প্রতিস্থাপন করুন
এটি পাওয়ারশেলের বর্তমান ওয়ার্কিং ডিরেক্টরিটি ব্যবহার করে আমার জন্য কাজ করেছে। আপনার FullName
সম্পত্তিটি ব্যবহার করা দরকার , বা এটি পাওয়ারশেল 5 সংস্করণে কাজ করবে না I আমার সমস্ত CSPROJ
ফাইলগুলিতে লক্ষ্য .NET ফ্রেমওয়ার্ক সংস্করণটি পরিবর্তন করা দরকার ।
gci -Recurse -Filter *.csproj |
% { (get-content "$($_.FullName)")
.Replace('<TargetFramework>net47</TargetFramework>', '<TargetFramework>net462</TargetFramework>') |
Set-Content "$($_.FullName)"}
কিছুটা পুরানো এবং ভিন্ন, যেমন একটি নির্দিষ্ট ফাইলের নামের সমস্ত ক্ষেত্রে আমার একটি নির্দিষ্ট লাইন পরিবর্তন করা দরকার।
এছাড়াও, Set-Content
ধারাবাহিক ফলাফলগুলি ফিরছিল না, তাই আমাকে অবলম্বন করতে হয়েছিল Out-File
।
নীচে কোড:
$FileName =''
$OldLine = ''
$NewLine = ''
$Drives = Get-PSDrive -PSProvider FileSystem
foreach ($Drive in $Drives) {
Push-Location $Drive.Root
Get-ChildItem -Filter "$FileName" -Recurse | ForEach {
(Get-Content $_.FullName).Replace($OldLine, $NewLine) | Out-File $_.FullName
}
Pop-Location
}
এই পাওয়ারশেল সংস্করণে এটিই আমার পক্ষে সবচেয়ে ভাল কাজ করেছে:
Major.Minor.Build.Revision
5.1.16299.98
সেট-সামগ্রী কমান্ডের জন্য ছোট সংশোধন। যদি অনুসন্ধানের স্ট্রিংটি না পাওয়া যায় Set-Content
তবে লক্ষ্য ফাইলটি কমান্ডটি ফাঁকা (ফাঁকা) করবে।
আপনি যে স্ট্রিংটির সন্ধান করছেন সেটির উপস্থিতি আছে কিনা তা আপনি প্রথমে যাচাই করতে পারেন। তা না হলে এটি কোনও কিছুর প্রতিস্থাপন করবে না।
If (select-string -path "c:\Windows\System32\drivers\etc\hosts" -pattern "String to look for") `
{(Get-Content c:\Windows\System32\drivers\etc\hosts).replace('String to look for', 'String to replace with') | Set-Content c:\Windows\System32\drivers\etc\hosts}
Else{"Nothing happened"}
set-content test.txt "hello hello world hello world hello"
এবং তারপরে (get-content .\test.txt).Replace("something", "awesome") | set-content .\test.txt
এই অনুসারে ফাইলটি খালি করবে না।