मैं PowerShell के साथ फ़ाइल में स्ट्रिंग की प्रत्येक घटना को कैसे बदल सकता हूं?


289

PowerShell का उपयोग करते हुए, मैं [MYID]दी गई फ़ाइल में मौजूद सभी सटीक घटनाओं को प्रतिस्थापित करना चाहता हूं MyValue। ऐसा करने का सबसे आसान तरीका क्या है?


इस प्रश्न के उत्तर में दिए गए मेमोरी खपत की तुलना में अधिक प्रभावी समाधान के लिए, बड़ी फ़ाइल में ढूँढें और बदलें देखें ।
मार्टिन प्रिक्रील

जवाबों:


444

उपयोग (V3 संस्करण):

(Get-Content c:\temp\test.txt).replace('[MYID]', 'MyValue') | Set-Content c:\temp\test.txt

या V2 के लिए:

(Get-Content c:\temp\test.txt) -replace '\[MYID\]', 'MyValue' | Set-Content c:\temp\test.txt

3
धन्यवाद - मुझे एक त्रुटि मिलती है "प्रतिस्थापित करें: विधि मंगलाचरण विफल हो गया क्योंकि [System.Object []] में 'प्रतिस्थापन' नामक एक विधि नहीं है।" हालांकि?
शौकिया

के रूप में \ PS में भागने काम करता है v4 मुझे अभी पता चला है। धन्यवाद।
EricE

4
यदि आप संशोधन को बचाना चाहते हैं तो @rob पाइप सेट-कंटेंट या आउट-फाइल करने का परिणाम है
Loïc MICHEL

2
मुझे त्रुटि "विधि मंगवाने में विफल रही क्योंकि [System.Object []] में 'प्रतिस्थापन' नाम की विधि नहीं है। क्योंकि मैं V3 संस्करण को एक मशीन पर चलाने की कोशिश कर रहा था जिसमें केवल V2 था।
एसएफगैग

5
चेतावनी: बड़ी फ़ाइलों (कुछ सौ मेगाबाइट्स) के खिलाफ इन लिपियों को चलाने से उचित मात्रा में मेमोरी हो सकती है। डी: बस सुनिश्चित करें कि आपके पास पर्याप्त सिर कमरा है अगर आप एक एक उत्पादन सर्वर पर चल रहा हो
neoscribe

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

नोट करें कि चारों ओर कोष्ठक (Get-Content file.txt)आवश्यक है:

कोष्ठक के बिना सामग्री को पढ़ा जाता है, एक समय में एक पंक्ति, और पाइप लाइन से नीचे तब तक बहती है जब तक वह आउट-फाइल या सेट-सामग्री तक नहीं पहुंच जाती है, जो एक ही फ़ाइल को लिखने की कोशिश करता है, लेकिन यह पहले से ही गेट-कंटेंट द्वारा खुला है और आपको मिलता है एक त्रुटि। कोष्ठक एक बार (खुले, पढ़ने और बंद) प्रदर्शन करने के लिए सामग्री पढ़ने के संचालन का कारण बनता है। तभी जब सभी लाइनों को पढ़ा गया है, उन्हें एक समय में एक पाइप किया जाता है और जब वे पाइप लाइन में अंतिम कमांड तक पहुंचते हैं तो उन्हें फ़ाइल में लिखा जा सकता है। यह $ सामग्री = सामग्री के समान है; $ सामग्री | कहाँ पे ...


5
अगर मैं कर सकता तो मैं अपने अपवोट को एक डाउनवोट में बदल देता। PowerShell 3 में यह चुपचाप फ़ाइल से सभी सामग्री को हटा देता है! यूओयू के Set-Contentबजाय का उपयोग करके Out-Fileएक चेतावनी मिलती है जैसे "यह प्रक्रिया '123.csv' फ़ाइल तक नहीं पहुंच सकती है क्योंकि इसका उपयोग किसी अन्य प्रक्रिया द्वारा किया जा रहा है।"
इयान सैमुअल मैकलीन एल्डर

9
यह तब नहीं होना चाहिए जब गेट-कंटेंट कोष्ठक में हो। वे ऑपरेशन को खोलने, पढ़ने और फ़ाइल को बंद करने का कारण बनते हैं ताकि आपको जो त्रुटि हो वह नहीं होनी चाहिए। क्या आप इसे एक नमूना पाठ फ़ाइल के साथ फिर से परीक्षण कर सकते हैं?
शाए लेवी

2
साथ Get-Contentकोष्ठक में यह काम करता है। क्या आप अपने उत्तर में बता सकते हैं कि कोष्ठक क्यों आवश्यक है? मैं अभी भी जगह लेंगे Out-Fileसाथ Set-Contentहै क्योंकि यह सुरक्षित है; यदि आप कोष्ठक को भूल जाते हैं तो यह लक्ष्य फ़ाइल को मिटा देने से बचाता है।
इयान सैमुअल मैकलीन एल्डर

6
फ़ाइल एन्कोडिंग UTF-8 के साथ समस्या । जब फ़ाइल सहेजता है, एन्कोडिंग को बदलता है। एक ही नहीं। stackoverflow.com/questions/5596982/… । मुझे लगता है कि सेट-सामग्री एन्कोडिंग फ़ाइल (जैसे UTF-8) पर विचार करती है। लेकिन आउट-फाइल नहीं
Kiquenet

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)

इसमें गेट-कंटेंट के साथ स्ट्रिंग-एरे के बजाय सिंगल स्ट्रिंग के साथ काम करने का फायदा है । तरीकों का भी ध्यान रखें कि आप ज्यादातर समय ध्यान रखे बिना फाइल (UTF-8 BOM इत्यादि) के एन्कोडिंग का ध्यान रखें।

इसके अलावा तरीके सेट-कंटेंट के जरिए गेट-कंटेंट और पाइपिंग का उपयोग करते हुए एल्गोरिथ्म के विपरीत लाइन एंडिंग (यूनिक्स लाइन एंडिंग का उपयोग किया जा सकता है) को गड़बड़ नहीं करते हैं ।

इसलिए मेरे लिए: कुछ चीजें जो वर्षों में टूट सकती हैं।

.NET कक्षाओं का उपयोग करते समय एक छोटी सी ज्ञात बात यह है कि जब आपने PowerShell विंडो में "[System.IO.File] ::" टाइप किया है, तो आप Tabकुंजी को वहां के तरीकों के माध्यम से ले जा सकते हैं।


आप कमांड के साथ तरीके भी देख सकते हैं [System.IO.File] | gm
fbehrens 11

यह विधि किसी सापेक्ष पथ को क्यों मानती है C:\Windows\System32\WindowsPowerShell\v1.0?
एड्रियन

ऐसा क्या? शायद ऐसा कुछ है कि PowerShell के भीतर .NET AppDomain शुरू होने के साथ कुछ करना है। हो सकता है, कि cd का उपयोग करते समय वर्तमान पथ अपडेट न हो। लेकिन यह एक शिक्षित अनुमान से अधिक नहीं है। मैंने इसका परीक्षण नहीं किया और न ही इसे देखा।
रोमिनेटर 007

2
यह पॉवर्सशेल के विभिन्न संस्करणों के लिए अलग-अलग कोड लिखने की तुलना में बहुत आसान है।
विलेम वैन केटविच

यह विधि भी सबसे तेज प्रतीत होती है। जोड़े कि विख्यात लाभ और प्रश्न के साथ होना चाहिए, "आप कुछ और क्यों इस्तेमाल करना चाहेंगे?"
DBADON

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 $_ }
KCD

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

(ऊपर दिए गए कोड का परीक्षण नहीं किया गया है।)

किसी दस्तावेज़ में पाठ को बदलने के लिए स्ट्रीमराइडर और स्ट्रीमराइटर का उपयोग करने के लिए संभवतः अधिक सुरुचिपूर्ण तरीका है, लेकिन यह आपको एक अच्छा प्रारंभिक बिंदु देना चाहिए।


मुझे लगता है कि सेट-सामग्री एन्कोडिंग फ़ाइल (जैसे UTF-8) पर विचार करती है। लेकिन नहीं बाहर फ़ाइल stackoverflow.com/questions/5596982/...
Kiquenet

2

मुझे पेलेट के विंडोज पॉवरशेल इन एक्शन से करने के लिए थोड़ा ज्ञात लेकिन आश्चर्यजनक रूप से अच्छा तरीका मिला । आप $ env: पथ के समान चर जैसी फ़ाइलों का संदर्भ दे सकते हैं, लेकिन आपको घुंघराले ब्रेस को जोड़ने की आवश्यकता है।

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

क्या होगा अगर फ़ाइल नाम चर में है $myFile?
44मेगामैन

@ --MegaMan हम्म केवल यह अब तक$a = 'file.txt'; invoke-expression "`${c:$a} = `${c:$a} -replace 'oldvalue','newvalue'"
js2010

2

यदि आपको कई फाइलों में स्ट्रिंग्स को बदलने की आवश्यकता है:

यह ध्यान दिया जाना चाहिए कि यहां तैनात विभिन्न तरीकों को पूरा होने में लगने वाले समय के संबंध में बेतहाशा भिन्न हो सकते हैं। मेरे लिए, मेरे पास नियमित रूप से बड़ी संख्या में छोटी फाइलें हैं। सबसे अधिक प्रदर्शन करने वाले का परीक्षण करने के लिए, मैंने XML की 402693 अलग-अलग फाइलों में 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

इसका श्रेय @ rominator007 को है

मैंने इसे एक फ़ंक्शन में लपेट लिया (क्योंकि आप इसे फिर से उपयोग करना चाह सकते हैं)

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

नोट: यह संवेदनशील मामला नहीं है !!!!!

इस पोस्ट देखें: String.Replace मामले की अनदेखी


0

यह मेरे लिए PowerShell में वर्तमान कार्यशील निर्देशिका का उपयोग करके काम करता है। आपको FullNameसंपत्ति का उपयोग करने की आवश्यकता है , या यह PowerShell संस्करण 5 में काम नहीं करेगा। मुझे अपनी सभी 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
}

इस PowerShell संस्करण में मेरे लिए यही सबसे अच्छा काम करता है:

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
StackOverflow में आपका स्वागत है! कृपया प्रारूपण का उपयोग करें, यदि आपको सहायता की आवश्यकता हो तो आप इस लेख को पढ़ सकते हैं ।
कोडनमेलांबाडा

1
यह सच नहीं है, अगर कोई सही उत्तर का उपयोग करता है और प्रतिस्थापित नहीं पाया जाता है, तो यह अभी भी फ़ाइल लिखता है, लेकिन कोई बदलाव नहीं है। उदाहरण के लिए, set-content test.txt "hello hello world hello world hello"इसके बाद (get-content .\test.txt).Replace("something", "awesome") | set-content .\test.txtफाइल खाली नहीं होगी।
16
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.