PowerShell का उपयोग करके किसी फ़ाइल में एकाधिक स्ट्रिंग्स को कैसे बदलें


107

मैं एक कॉन्फ़िगरेशन फ़ाइल को अनुकूलित करने के लिए एक स्क्रिप्ट लिख रहा हूं। मैं इस फ़ाइल के भीतर स्ट्रिंग के कई उदाहरणों को बदलना चाहता हूं, और मैंने काम करने के लिए पावरशेल का उपयोग करने की कोशिश की।

यह एक सिंगल रिप्ले के लिए ठीक काम करता है, लेकिन मल्टीपल रिप्लेस करना बहुत धीमा होता है क्योंकि हर बार इसे पूरी फाइल को फिर से पार्स करना पड़ता है, और यह फाइल बहुत बड़ी होती है। स्क्रिप्ट इस तरह दिखती है:

$original_file = 'path\filename.abc'
$destination_file =  'path\filename.abc.new'
(Get-Content $original_file) | Foreach-Object {
    $_ -replace 'something1', 'something1new'
    } | Set-Content $destination_file

मुझे ऐसा कुछ चाहिए, लेकिन मुझे नहीं पता कि इसे कैसे लिखना है:

$original_file = 'path\filename.abc'
$destination_file =  'path\filename.abc.new'
(Get-Content $original_file) | Foreach-Object {
    $_ -replace 'something1', 'something1aa'
    $_ -replace 'something2', 'something2bb'
    $_ -replace 'something3', 'something3cc'
    $_ -replace 'something4', 'something4dd'
    $_ -replace 'something5', 'something5dsf'
    $_ -replace 'something6', 'something6dfsfds'
    } | Set-Content $destination_file

जवाबों:


167

एक विकल्प -replaceपरिचालन को एक साथ श्रृंखलाबद्ध करना है । `प्रत्येक पंक्ति के अंत में न्यू लाइन पलायन, अगली पंक्ति पर अभिव्यक्ति को पार्स जारी रखने के लिए PowerShell के कारण:

$original_file = 'path\filename.abc'
$destination_file =  'path\filename.abc.new'
(Get-Content $original_file) | Foreach-Object {
    $_ -replace 'something1', 'something1aa' `
       -replace 'something2', 'something2bb' `
       -replace 'something3', 'something3cc' `
       -replace 'something4', 'something4dd' `
       -replace 'something5', 'something5dsf' `
       -replace 'something6', 'something6dfsfds'
    } | Set-Content $destination_file

एक अन्य विकल्प एक मध्यवर्ती चर आवंटित करना होगा:

$x = $_ -replace 'something1', 'something1aa'
$x = $x -replace 'something2', 'something2bb'
...
$x

$ मूल_फाइल == $ गंतव्य_फाइल हो सकता है? जैसा कि मैं अपने स्रोत के रूप में एक ही फाइल को संशोधित कर रहा हूं?
cquadrini

जिस तरह से PowerShell cmdlets उनके इनपुट / ouput को स्ट्रीम करते हैं, मुझे नहीं लगता कि यह एक ही फाइल को एक ही पाइपलाइन में लिखने के लिए काम करेगा। हालाँकि, आप ऐसा कुछ कर सकते थे $c = Get-Content $original_file; $c | ... | Set-Content $original_file
दहलबीक

क्या आपको सेट-सामग्री का उपयोग करके फ़ाइल एन्कोडिंग के बारे में समस्या है जो मूल एन्कोडिंग को नहीं बनाती है? उदाहरण के लिए UTF-8 या ANSI एन्कोडिंग।
किकेनेट

1
हाँ PowerShell है ... उस तरह unhelpful। आपको खुद को एन्कोडिंग का पता लगाना होगा, जैसे github.com/dahlbyk/posh-git/blob/…
dahlbyk

24

जॉर्ज हावर्थ द्वारा पद प्राप्त करने के लिए एक से अधिक प्रतिस्थापन के साथ ठीक से काम करने से आपको ब्रेक को हटाने की आवश्यकता होती है, आउटपुट को एक चर ($ लाइन) पर असाइन करें और फिर चर को आउटपुट करें:

$lookupTable = @{
    'something1' = 'something1aa'
    'something2' = 'something2bb'
    'something3' = 'something3cc'
    'something4' = 'something4dd'
    'something5' = 'something5dsf'
    'something6' = 'something6dfsfds'
}

$original_file = 'path\filename.abc'
$destination_file =  'path\filename.abc.new'

Get-Content -Path $original_file | ForEach-Object {
    $line = $_

    $lookupTable.GetEnumerator() | ForEach-Object {
        if ($line -match $_.Key)
        {
            $line = $line -replace $_.Key, $_.Value
        }
    }
   $line
} | Set-Content -Path $destination_file

यह अब तक का सबसे अच्छा तरीका है। एकमात्र मुद्दा यह है कि मुझे एक ही स्रोत / गंतव्य फ़ाइल पथों का उपयोग करने के लिए पहले पूरी सामग्री को एक चर में पढ़ना था।
कोणीय काल

यह सबसे अच्छा उत्तर की तरह दिखता है, हालांकि मैंने इसके साथ कुछ अजीब व्यवहार देखा है जो गलत तरीके से मेल खाता है। यानी मामले में जहां आपके पास हैश वैल्यू है जिसमें स्ट्रिंग्स (0x0, 0x1, 0x100, 0x10000) और 0x10000 0x1 से मेल खाते हैं।
लोरक

13

PowerShell के संस्करण 3 के साथ आप कॉल को एक साथ बदल सकते हैं:

 (Get-Content $sourceFile) | ForEach-Object {
    $_.replace('something1', 'something1').replace('somethingElse1', 'somethingElse2')
 } | Set-Content $destinationFile

ठीक + धाराप्रवाह स्वाद
hdoghmen

10

मान लें कि आपके पास प्रति पंक्ति में केवल एक 'something1'या 'something2'आदि हो सकते हैं, आप एक लुकअप तालिका का उपयोग कर सकते हैं:

$lookupTable = @{
    'something1' = 'something1aa'
    'something2' = 'something2bb'
    'something3' = 'something3cc'
    'something4' = 'something4dd'
    'something5' = 'something5dsf'
    'something6' = 'something6dfsfds'
}

$original_file = 'path\filename.abc'
$destination_file =  'path\filename.abc.new'

Get-Content -Path $original_file | ForEach-Object {
    $line = $_

    $lookupTable.GetEnumerator() | ForEach-Object {
        if ($line -match $_.Key)
        {
            $line -replace $_.Key, $_.Value
            break
        }
    }
} | Set-Content -Path $destination_file

आप उन लोगों में से एक से अधिक हो सकता है, तो बस हटाने breakमें ifबयान।


मुझे लगता है कि ट्रॉयब्रमले ने किसी भी लाइन को लिखने के लिए अंतिम पंक्ति से ठीक पहले $ लाइन जोड़ी थी जिसमें कोई बदलाव नहीं था। ठीक है। मेरे मामले में मुझे केवल हर पंक्ति को प्रतिस्थापन की आवश्यकता थी।
क्लिफक्लोफ

8

एक तीसरा विकल्प, एक पाइप लाइन वाले वन-लाइनर के लिए -replaces है:

PS> ("ABC" -replace "B","C") -replace "C","D"
ADD

तथा:

PS> ("ABC" -replace "C","D") -replace "B","C"
ACD

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

-Replace एक Comparison Operator है, जो किसी ऑब्जेक्ट को स्वीकार करता है और संभवतः संशोधित ऑब्जेक्ट देता है। यही कारण है कि आप ऊपर दिखाए गए अनुसार उन्हें स्टैक या घोंसला कर सकते हैं।

कृपया देखें:

help about_operators
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.