আমি কীভাবে পাওয়ারসেলের সাহায্যে কোনও স্ট্রিংয়ের প্রতিটি ঘটনাকে প্রতিস্থাপন করতে পারি?


289

পাওয়ারশেল ব্যবহার করে, আমি [MYID]একটি প্রদত্ত ফাইলের সাথে সমস্ত সঠিক উপস্থিতি প্রতিস্থাপন করতে চাই MyValue। এটি করার সহজতম উপায় কী?


এই প্রশ্নের উত্তরের প্রস্তাবিত চেয়ে মেমরির ব্যবহারের ক্ষেত্রে আরও কার্যকর সমাধানের জন্য, একটি বৃহত ফাইলে সন্ধান করুন এবং প্রতিস্থাপন দেখুন ।
মার্টিন প্রিক্রিল

উত্তর:


444

(ভি 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

3
ধন্যবাদ - আমি একটি ত্রুটি পেয়েছি "প্রতিস্থাপন: পদ্ধতির অনুরোধ ব্যর্থ হয়েছে কারণ [সিস্টেম.অজেক্ট []] এ 'প্রতিস্থাপন' নামের একটি পদ্ধতি নেই।" যদিও?
অপেশাদার

escape যেমন পালানো PS v4 তে কাজ করে আমি সন্ধান করেছি। ধন্যবাদ।
এরিক

4
@rob ফলাফলটি সেট-সামগ্রী বা আউট-ফাইলের কাছে পাইপ করুন যদি আপনি এই পরিবর্তনটি সংরক্ষণ করতে চান
Loïc MICHEL

2
আমি ত্রুটি পেয়েছি "পদ্ধতির অনুরোধ ব্যর্থ হয়েছে কারণ [সিস্টেম.অজেক্ট []] এ 'প্রতিস্থাপন' নামে একটি পদ্ধতি নেই" " কারণ আমি এমন কোনও মেশিনে ভি 3 সংস্করণ চালানোর চেষ্টা করছিলাম যা কেবল ভি 2 ছিল।
এসএফ্লেগ

5
সতর্কতা: বড় ফাইলগুলির (এই দুইশত মেগাবাইট বা তাই) বিরুদ্ধে এই স্ক্রিপ্টগুলি চালানো মোটামুটি পরিমাণ স্মৃতি খেয়ে ফেলতে পারে। আপনি যদি একটি প্রোডাকশন সার্ভারে চলমান থাকেন তবে আপনার পর্যাপ্ত হেড রুম রয়েছে তা নিশ্চিত করুন: ডি
নয়েস্ক্রাইব

89
(Get-Content file.txt) | 
Foreach-Object {$_ -replace '\[MYID\]','MyValue'}  | 
Out-File file.txt

আশেপাশে প্রথম বন্ধনী (Get-Content file.txt)আবশ্যক:

প্রথম বন্ধনী ছাড়া সামগ্রীটি একবারে এক লাইনে পড়া হয় এবং পাইপলাইনটি প্রবাহিত না হওয়া অবধি প্রবাহিত হয় যতক্ষণ না এটি ফাইল বা সেট-সামগ্রীতে পৌঁছে যায়, যা একই ফাইলটিতে লেখার চেষ্টা করে তবে এটি ইতিমধ্যে গেট-কনটেন্ট দ্বারা খোলা থাকে এবং আপনি পান একটি ভুল. প্রথম বন্ধনী কন্টেন্ট রিডিংয়ের ক্রিয়াকলাপ একবার (খোলা, পড়ুন এবং বন্ধ করুন) সম্পাদন করে। তারপরে সমস্ত লাইনগুলি পড়ার পরে, সেগুলি একবারে একবারে পাইপ দেওয়া হয় এবং পাইপলাইনে শেষ কমান্ডে পৌঁছলে সেগুলি ফাইলে লেখা যায়। এটি $ সামগ্রী = সামগ্রী হিসাবে একই; $ সামগ্রী | কোথায় ...


5
আমি যদি পারতাম তবে আমার উপনোটকে ডাউনটাতে বদলে ফেলতাম। পাওয়ারশেল 3 এ এটি নীরবে ফাইল থেকে সমস্ত সামগ্রী মুছে দেয়! আপনার Set-Contentপরিবর্তে ব্যবহার করে Out-Fileএকটি সতর্কতা পান যেমন "প্রক্রিয়াটি '123.csv' ফাইলটি অ্যাক্সেস করতে পারে না কারণ এটি অন্য প্রক্রিয়া দ্বারা ব্যবহৃত হচ্ছে।"
আইয়েন স্যামুয়েল ম্যাকলিন বয়স্ক

9
গেট-কন্টেন্টটি প্রথম বন্ধনে থাকলে এটি হওয়া উচিত নয়। এগুলি অপারেশনটিকে ফাইলটি খোলার, পড়ার এবং বন্ধ করার কারণ করে যাতে আপনার ত্রুটিটি ঘটবে না। আপনি কি আবার কোনও নমুনা পাঠ্য ফাইল দিয়ে এটি পরীক্ষা করতে পারেন?
শাই লেভি

2
সঙ্গে Get-Contentপ্রথম বন্ধনী মধ্যে এটি কাজ করে। আপনার উত্তরটিতে ব্যাখ্যা করতে পারেন কেন প্রথম বন্ধনী প্রয়োজনীয়? আমি এখনও প্রতিস্থাপন করবে Out-Fileসঙ্গে Set-Contentকারণ এটি নিরাপদ; এটি যদি আপনি প্রথম বন্ধনী ভুলে যান তবে লক্ষ্য ফাইলটি মুছে ফেলার হাত থেকে রক্ষা করে।
আইয়েন স্যামুয়েল ম্যাকলিন প্রবীণ

6
ইউটিএফ -8 ফাইল এনকোডিংয়ে সমস্যা । ফাইলটি সংরক্ষণ করার পরে, এনকোডিং পরিবর্তন করে। একই নয়. stackoverflow.com/questions/5596982/… । আমি মনে করি সেট-সামগ্রীগুলি এনকোডিং ফাইলটিকে (ইউটিএফ -8 এর মতো) বিবেচনা করে। তবে আউট-ফাইল নয়
কিউইনেট

1
এই সমাধানটি অযৌক্তিকভাবে বিভ্রান্তিকর এবং যখন আমি এটি ব্যবহার করি তখন সমস্যা সৃষ্টি করে। আমি একটি কনফিগার ফাইল আপডেট করছি যা তাৎক্ষণিকভাবে ইনস্টলেশন প্রক্রিয়া দ্বারা ব্যবহৃত হয়েছিল। কনফিগার ফাইলটি এখনও প্রক্রিয়া দ্বারা রাখা হয়েছিল এবং ইনস্টলেশনটি ব্যর্থ হয়েছিল। Set-Contentপরিবর্তে ব্যবহার Out-Fileকরা আরও ভাল এবং নিরাপদ সমাধান। দুঃখিত ডাউন ডাউন করতে হবে।
মার্টিন বাসিস্তা

81

নীচের উদাহরণে দেখা হিসাবে আমি .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
fbehrens

এই পদ্ধতিটি কেন থেকে আপেক্ষিক পথ ধরে C:\Windows\System32\WindowsPowerShell\v1.0?
এড্রিয়ান

তাই নাকি? একটি নেট নেট অ্যাপডোমেন পাওয়ারশেলের মধ্যে যেভাবে শুরু হয়েছিল তার সাথে সম্ভবত এটির কোনও সম্পর্ক রয়েছে। হতে পারে, সিডি ব্যবহার করার সময় বর্তমান পাথ আপডেট হয় না। তবে এটি শিক্ষিত অনুমান ছাড়া আর কিছু নয়। আমি এটি পরীক্ষা করিনি বা এটি সন্ধান করিনি।
rominator007

2
পাওয়ারশেলের বিভিন্ন সংস্করণের জন্য আলাদা কোড লেখার চেয়ে এটি অনেক সহজ।
উইলেম ভ্যান কেটভিচ

এই পদ্ধতিটিও দ্রুততম বলে মনে হয়। দম্পতি যা উল্লেখযোগ্য সুবিধাগুলি সহ এবং প্রশ্নটি হওয়া উচিত, "আপনি অন্য কিছু কেন ব্যবহার করতে চান?"
ডিবিএডন

21

উপরের একটিটি কেবল "একটি ফাইল" এর জন্য চালিত হয় তবে আপনি এটি আপনার ফোল্ডারের মধ্যে একাধিক ফাইলের জন্য চালাতে পারেন:

Get-ChildItem 'C:yourfile*.xml' -Recurse | ForEach {
     (Get-Content $_ | ForEach  { $_ -replace '[MYID]', 'MyValue' }) |
     Set-Content $_
}

লক্ষ্য করুন যে আমি .xML ব্যবহার করেছি তবে আপনি .txt দিয়ে প্রতিস্থাপন করতে পারেন
জন ভি হবস জুনিয়র

খুশী হলাম। বিকল্প হিসাবে অভ্যন্তরটি ব্যবহার করে foreachআপনি এটি করতে পারেনGet-ChildItem 'C:\folder\file*.xml' -Recurse | ForEach { (Get-Content $_).Replace('[MYID]', 'MyValue') | Set-Content $_ }
কেসিডি

1
আসলে, আপনার সেই অভ্যন্তরটি দরকার foreach, কারণ গেট-কন্টেন্ট এমন কিছু করে যা আপনি প্রত্যাশা করতে পারেন না ... এটি স্ট্রিংগুলির একটি অ্যারে প্রদান করে, যেখানে প্রতিটি স্ট্রিং ফাইলের একটি লাইন। আপনি যদি কোনও চলমান স্ক্রিপ্টের চেয়ে পৃথক স্থানে থাকা কোনও ডিরেক্টরি (এবং উপ ডিরেক্টরি) দিয়ে লুপিং করেন তবে আপনি এর মতো কিছু চাইবেন: Get-ChildItem $Directory -File -Recurse | ForEach { (Get-Content $_.FullName) | ForEach { $_ -replace '[MYID]', 'MyValue' } | Set-Content $_.FullName }যেখানে $Directoryফাইলগুলি সংশোধন করতে চান সেই ডিরেক্টরিটি কোথায় ।
বার্ডামংম্যান

1
"উপরে একটি" কি উত্তর?
পিটার মর্টেনসেন

10

আপনি এরকম কিছু চেষ্টা করতে পারেন:

$path = "C:\testFile.txt"
$word = "searchword"
$replacement = "ReplacementText"
$text = get-content $path 
$newText = $text -replace $word,$replacement
$newText > $path

7

এটি আমি ব্যবহার করি তবে এটি বড় টেক্সট ফাইলগুলিতে ধীর হয়।

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()
   }
}

(উপরের কোডটি পরীক্ষা করা হয়নি))

ডকুমেন্টে পাঠ্য প্রতিস্থাপনের জন্য স্ট্রিমরিডার এবং স্ট্রিমউইটার সম্ভবত ব্যবহার করার আরও একটি দুর্দান্ত উপায় আছে তবে এটি আপনাকে একটি ভাল সূচনা পয়েন্ট দেয়।


আমি মনে করি সেট-সামগ্রীগুলি এনকোডিং ফাইলটিকে (ইউটিএফ -8 এর মতো) বিবেচনা করে। কিন্তু না আউট-ফাইলের stackoverflow.com/questions/5596982/...
Kiquenet

2

পাইটের উইন্ডোজ পাওয়ারশেল ইন অ্যাকশন থেকে এটি করার জন্য আমি কিছুটা পরিচিত তবে আশ্চর্যরকম দুর্দান্ত উপায় পেয়েছি । আপনি ভেরিয়েবলের মতো ফাইলগুলি রেফারেন্স করতে পারেন, similar env: পাথের মতো, তবে আপনার কোঁকড়া ধনুর্বন্ধনী যোগ করতে হবে।

${c:file.txt} = ${c:file.txt} -replace 'oldvalue','newvalue'

ফাইলনাম যেমন ভেরিয়েবলের মধ্যে থাকে তবে কী হবে $myFile?
gamegaMan

@ ΩmegaMan এই পর্যন্ত কেবল হুম$a = 'file.txt'; invoke-expression "`${c:$a} = `${c:$a} -replace 'oldvalue','newvalue'"
js2010

2

যদি আপনার একাধিক ফাইলে স্ট্রিংগুলি প্রতিস্থাপন করতে হয়:

এটি লক্ষ করা উচিত যে এখানে পোস্ট করা বিভিন্ন পদ্ধতিগুলি সম্পূর্ণ হতে সময়টি বিবেচনা করে বুনোভাবে আলাদা হতে পারে। আমার জন্য, আমার নিয়মিত ছোট ছোট ফাইল থাকে। সর্বাধিক পারফরম্যান্ট কী তা পরীক্ষা করতে, আমি 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
#>

প্রশ্নটি ছিল একটি দেওয়া ফাইলটিতে স্ট্রিংগুলি প্রতিস্থাপন করার বিষয়ে, একাধিক ফাইল নয়।
পিএল

1

ক্রেডিট @ রোমিনেটর 700

আমি এটিকে একটি ফাংশনে আবৃত করেছি (কারণ আপনি এটি আবার ব্যবহার করতে চাইতে পারেন)

function Replace-AllStringsInFile($SearchString,$ReplaceString,$FullPathToFile)
{
    $content = [System.IO.File]::ReadAllText("$FullPathToFile").Replace("$SearchString","$ReplaceString")
    [System.IO.File]::WriteAllText("$FullPathToFile", $content)
}

দ্রষ্টব্য: এটি কেস সংবেদনশীল নয় !!!!!

পোস্টটি দেখুন: স্ট্রিং। প্রতিস্থাপনের ক্ষেত্রে প্রতিস্থাপন করুন


0

এটি পাওয়ারশেলের বর্তমান ওয়ার্কিং ডিরেক্টরিটি ব্যবহার করে আমার জন্য কাজ করেছে। আপনার FullNameসম্পত্তিটি ব্যবহার করা দরকার , বা এটি পাওয়ারশেল 5 সংস্করণে কাজ করবে না I আমার সমস্ত CSPROJফাইলগুলিতে লক্ষ্য .NET ফ্রেমওয়ার্ক সংস্করণটি পরিবর্তন করা দরকার ।

gci -Recurse -Filter *.csproj |
% { (get-content "$($_.FullName)")
.Replace('<TargetFramework>net47</TargetFramework>', '<TargetFramework>net462</TargetFramework>') |
 Set-Content "$($_.FullName)"}

0

কিছুটা পুরানো এবং ভিন্ন, যেমন একটি নির্দিষ্ট ফাইলের নামের সমস্ত ক্ষেত্রে আমার একটি নির্দিষ্ট লাইন পরিবর্তন করা দরকার।

এছাড়াও, 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


-1

সেট-সামগ্রী কমান্ডের জন্য ছোট সংশোধন। যদি অনুসন্ধানের স্ট্রিংটি না পাওয়া যায় 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"}

3
স্ট্যাকওভারফ্লোতে আপনাকে স্বাগতম! বিন্যাস ব্যবহার করুন, আপনার যদি সাহায্যের প্রয়োজন হয় তবে আপনি এই নিবন্ধটি পড়তে পারেন।
কোডেনামলাম্বদা

1
এটি সত্য নয়, যদি কেউ সঠিক উত্তর ব্যবহার করে এবং প্রতিস্থাপনটি পাওয়া যায় না, তবে এটি ফাইলটি লিখতে থাকে, তবে কোনও পরিবর্তন হয় না। উদাহরণস্বরূপ set-content test.txt "hello hello world hello world hello"এবং তারপরে (get-content .\test.txt).Replace("something", "awesome") | set-content .\test.txtএই অনুসারে ফাইলটি খালি করবে না।
সিয়ানটিক
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.