PowerShell स्क्रिप्ट एक विशिष्ट एक्सटेंशन के साथ सभी फ़ाइलों को खोजने और बदलने के लिए


123

मेरे पास Windows Server 2008 पर कई कॉन्फ़िगरेशन फ़ाइलें हैं जैसे कि:

C:\Projects\Project_1\project1.config

C:\Projects\Project_2\project2.config

मेरे विन्यास में मुझे इस तरह की जगह एक स्ट्रिंग करने की आवश्यकता है:

<add key="Environment" value="Dev"/>

हो जाएगा:

<add key="Environment" value="Demo"/>

मैंने बैच स्क्रिप्टिंग का उपयोग करने के बारे में सोचा था, लेकिन ऐसा करने का कोई अच्छा तरीका नहीं था, और मैंने सुना कि पावरशेल स्क्रिप्टिंग के साथ आप आसानी से इसे देख सकते हैं। मुझे ढूंढने / बदलने के उदाहरण मिले हैं, लेकिन मैं एक ऐसे तरीके की उम्मीद कर रहा था, जो मेरे C: \ Projects निर्देशिका के भीतर सभी फ़ोल्डरों को पीछे छोड़ दे और '.config' एक्सटेंशन के साथ समाप्त होने वाली किसी भी फ़ाइल को ढूंढें। जब यह एक मिल जाता है, तो मैं इसे अपने स्ट्रिंग मानों को बदलने के लिए चाहता हूं।

कोई भी अच्छा संसाधन यह पता लगाने के लिए कि यह कैसे करना है या कोई PowerShell गुरु जो कुछ अंतर्दृष्टि प्रदान कर सकता है?


1
हमें बताएं कि आपको कैसे मिला या अगर फ़ाइलों के साथ कुछ विषम स्वरूपण मुद्दे थे जिन्हें संबोधित करने की आवश्यकता थी। समस्या के बारे में एक अच्छी बात यह है कि उत्पादन कोड को प्रभावित किए बिना इसका परीक्षण किया जाता है
Robben_Ford_Fan_boy

जवाबों:


178

यहाँ मेरे सिर के शीर्ष पर पहला प्रयास है।

$configFiles = Get-ChildItem . *.config -rec
foreach ($file in $configFiles)
{
    (Get-Content $file.PSPath) |
    Foreach-Object { $_ -replace "Dev", "Demo" } |
    Set-Content $file.PSPath
}

3
मैं यह जोड़ना चाहूंगा कि समाधान प्रदान करने वाले परीक्षण सभी काम कर रहे हैं, लेकिन यह पठनीयता के लिए सबसे आसान था। मैं इसे एक सहकर्मी को सौंपने में सक्षम था और वह आसानी से समझ सकता था कि क्या चल रहा था। सहायता के लिए धन्यवाद।
ब्रैंडन

11
इसके लिए उपनिर्देशिकाओं की फाइलों में काम करने के लिए, आपको ".PSPath" की आवश्यकता होगी। दिलचस्प बात यह है कि जब मैंने इस सामग्री को बिना (ए) के पास बनाने की कोशिश की, तो यह लेखन-सामग्री में विफल रही क्योंकि फ़ाइल लॉक थी।
फ्रैंक श्वेतेरमैन

25
लघु संस्करण (सामान्य उपनाम का उपयोग किया जाता है):ls *.config -rec | %{ $f=$_; (gc $f.PSPath) | %{ $_ -replace "Dev", "Demo" } | sc $f.PSPath }
अरेटोम

5
@Artyom के .बाद मत भूलना ls। अपने आप से डगमगा गया।
शुद्ध

5
यदि आप सभी फ़ाइलों पर चलने के लिए * .config को निकाल देंगे, तो फ़ोल्डर्स के कारण अनधिकृत रूप से अपवाद भी हो सकता है। आप जोड़ सकते हैं-Get-ChildItem के लिए फ़िले फ़िल्टर ... यह पता लगाने के लिए कुछ समय लिया
आमिर काटज़

32

PowerShell एक अच्छा विकल्प है;) दी गई निर्देशिका में फ़ाइलों को एन्यूमरेट करना, उन्हें पढ़ना और प्रक्रिया करना बहुत आसान है।

स्क्रिप्ट इस तरह दिख सकती है:

Get-ChildItem C:\Projects *.config -recurse |
    Foreach-Object {
        $c = ($_ | Get-Content) 
        $c = $c -replace '<add key="Environment" value="Dev"/>','<add key="Environment" value="Demo"/>'
        [IO.File]::WriteAllText($_.FullName, ($c -join "`r`n"))
    }

मैंने आपके लिए पठनीय होने के लिए कोड को अधिक पंक्तियों में विभाजित किया है। ध्यान दें कि आप इसके बजाय सेट-सामग्री का उपयोग कर सकते हैं [IO.File]::WriteAllText, लेकिन यह अंत में नई रेखा जोड़ता है। साथ मेंWriteAllText आप बच सकते हैं।

अन्यथा कोड इस तरह दिख सकता है $c | Set-Content $_.FullName:।


14

यह दृष्टिकोण अच्छी तरह से काम करता है:

gci C:\Projects *.config -recurse | ForEach {
  (Get-Content $_ | ForEach {$_ -replace "old", "new"}) | Set-Content $_ 
}
  • "पुराने" और "नए" को उनके संबंधित मूल्यों में बदलें (या चर का उपयोग करें)।
  • कोष्ठक मत भूलना - जिसके बिना आपको एक अभिगमन त्रुटि प्राप्त होगी।

इसलिए मैं एक के साथ यह सबकुछ एक्सप्रेशन के लिए गया - लेकिन मुझे इसके Get-Content $_साथ बदलना पड़ा Get-Content $_.FullName, और Set-Contentइसके लिए इसके बराबर की फाइलें जो रूट पर नहीं थीं।
मैट व्हिटफील्ड

11

मैं xml और xpath के साथ जाऊंगा:

dir C:\Projects\project_*\project*.config -recurse | foreach-object{  
   $wc = [xml](Get-Content $_.fullname)
   $wc.SelectNodes("//add[@key='Environment'][@value='Dev']") | Foreach-Object {$_.value = 'Demo'}  
   $wc.Save($_.fullname)  
}

11

यह पॉवरशेल उदाहरण एक फ़ोल्डर में स्ट्रिंग "\ foo \" के सभी उदाहरणों के लिए दिखता है और इसके सबफ़ोल्डर्स, "\ foo \" को "\ bar \" के साथ बदल देता है और उन फ़ाइलों को पुनर्प्राप्त नहीं करता है जिनमें स्ट्रिंग \ "foo \" नहीं होती है "इस तरह आप फ़ाइल को अंतिम अद्यतन डेटाइम स्टैम्प को नष्ट नहीं करते हैं जहाँ स्ट्रिंग नहीं मिली थी:

Get-ChildItem  -Path C:\YOUR_ROOT_PATH\*.* -recurse 
 | ForEach {If (Get-Content $_.FullName | Select-String -Pattern '\\foo\\') 
           {(Get-Content $_ | ForEach {$_ -replace '\\foo\\', '\bar\'}) | Set-Content $_ }
           }

7

मुझे @Artyom की टिप्पणी उपयोगी लगी लेकिन दुर्भाग्य से उन्होंने कोई जवाब नहीं दिया।

यह छोटा संस्करण है, मेरी राय में सबसे अच्छा संस्करण, स्वीकृत उत्तर का;

ls *.config -rec | %{$f=$_; (gc $f.PSPath) | %{$_ -replace "Dev", "Demo"} | sc $f.PSPath}

1
यदि कोई ऐसा करता है, तो जैसा कि मैंने किया है - बैच फ़ाइल से सीधे इसे निष्पादित करने की तलाश में - यह इस तरह से एक कमांड निष्पादित करते समय उपनाम के foreach-objectबजाय उपयोग करने में मदद कर सकता है %। अन्यथा, इसके परिणामस्वरूप त्रुटि हो सकती है:Expressions are only allowed as the first element of a pipeline
डस्टिन हाल्टड

शॉर्ट हमेशा बेहतर नहीं होता है, यह अधिक स्पष्ट है कि लंबे संस्करण में क्या हो रहा है।
निक एन

@NickN। ठीक है, ठीक है। यह इस बात पर निर्भर करता है कि आपका उद्देश्य क्या है। मैं इसे POB के रूप में चिह्नित करूंगा;)
M--

6

मैंने एक फ़ाइल में पाठ को बदलने के लिए थोड़ा सहायक फ़ंक्शन लिखा है:

function Replace-TextInFile
{
    Param(
        [string]$FilePath,
        [string]$Pattern,
        [string]$Replacement
    )

    [System.IO.File]::WriteAllText(
        $FilePath,
        ([System.IO.File]::ReadAllText($FilePath) -replace $Pattern, $Replacement)
    )
}

उदाहरण:

Get-ChildItem . *.config -rec | ForEach-Object { 
    Replace-TextInFile -FilePath $_ -Pattern 'old' -Replacement 'new' 
}

4

पुनरावर्ती प्रतिस्थापन करते समय, पथ और फ़ाइल नाम को शामिल करने की आवश्यकता होती है:

Get-ChildItem -Recurse | ForEach {  (Get-Content $_.PSPath | 
ForEach {$ -creplace "old", "new"}) | Set-Content $_.PSPath }

यह wil आपके वर्तमान डायरेक्टरी के आपके फोल्डर की सभी फाइलों में "नए" केस-सेंसिव के साथ "पुराने" को बदल देता है।


आपके उत्तर के ".PPath" भाग ने वास्तव में मेरी मदद की। लेकिन मुझे आंतरिक "{$" को "$ _" में बदलना पड़ा। मैं आपके उत्तर को संपादित करूँगा, लेकिन मैं आपके -creplace भाग का उपयोग नहीं कर रहा हूँ - मैं .PSPath के साथ स्वीकृत उत्तर का उपयोग कर रहा हूँ
aaaa bbbb
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.