2011-08-25 15 views
10

मान लीजिए कि मेरे पास स्ट्रिंग्स (सूची ए और सूची बी) की दो सूचियां हैं, प्रत्येक सूची में सटीक प्रविष्टियों, एन, के साथ, और मैं बी के nth तत्व के साथ ए के nth तत्व की सभी घटनाओं को प्रतिस्थापित करना चाहता हूं। यूनिक्स में एक फ़ाइल में (आदर्श रूप से बैश स्क्रिप्टिंग का उपयोग कर)।यूनिक्स फ़ाइल में किसी अन्य सूची के साथ स्ट्रिंग्स की सूची को प्रतिस्थापित करने का एक प्रभावी तरीका क्या है?

ऐसा करने का सबसे प्रभावी तरीका क्या है?

एन 0 कॉल करने के लिए एक अक्षम तरीका होगा "sed s/stringA/stringB/g"।

उत्तर

9

यह एक ही पास में करेगा। यह सूची ए और सूचीबी को अजीब सरणी में पढ़ता है, फिर लिनपूट की प्रत्येक पंक्ति के लिए, यह प्रत्येक शब्द की जांच करता है और यदि शब्द सूची ए में पाया जाता है, तो शब्द को सूची बी में इसी शब्द से बदल दिया जाता है।

awk ' 
    FILENAME == ARGV[1] { listA[$1] = FNR; next } 
    FILENAME == ARGV[2] { listB[FNR] = $1; next } 
    { 
     for (i = 1; i <= NF; i++) { 
      if ($i in listA) { 
       $i = listB[listA[$i]] 
      } 
     } 
     print 
    } 
' listA listB filename > filename.new 
mv filename.new filename 

मैं लिस्टा में तार संभालने कर रहा हूँ खाली स्थान के (awk के डिफ़ॉल्ट क्षेत्र विभाजक)

+1

अच्छा, कुल मिलाकर, लेकिन एक संभावित समस्या के साथ। यह समाधान आवश्यक रूप से उन रेखाओं पर इंटरैक्टिव रिक्ति को संरक्षित नहीं करता है जहां परिवर्तन किए जाते हैं; व्हाइटस्पेस के रन एक ही स्थान पर बदल जाते हैं। चूंकि हम पाठ की प्रकृति को नहीं जानते हैं, इसलिए यह कोई समस्या नहीं हो सकती है और यहां तक ​​कि एक लाभ भी हो सकता है। वैसे भी, मेरे द्वारा +1। –

+0

यह नीचे दिए गए समाधान से स्पष्ट रूप से अधिक कुशल है जो एक स्क्रिप्ट स्क्रिप्ट लिखता है। 3 मिनट में समाप्त हुआ जो sed समाधान का उपयोग करके 3 दिन लिया। यह केवल पूरे शब्दों को प्रतिस्थापित करता है, भले ही यह नहीं पूछा गया था। –

+0

इस उद्देश्य को हल करती है, लेकिन कैसे सफेद रिक्त स्थान को बचाने के लिये? ऐसा लगता है कि अजीब स्क्रिप्ट उन्हें केवल एक सफेद जगह के साथ बदल देती है। – Guru

6

sed पर एक कॉल करें जो sed script लिखता है, और दूसरा इसका उपयोग करने के लिए? अपनी सूची फ़ाइलें listA और listB, तो में हैं:

paste -d : listA listB | sed 's/\([^:]*\):\([^:]*\)/s%\1%\2%/' > sed.script 
sed -f sed.script files.to.be.mapped.* 

मैं 'शब्द' के बारे में कुछ व्यापक मान्यताओं बना रही हूँ बृहदान्त्र या प्रतिशत प्रतीक वाले नहीं है, लेकिन आपको लगता है कि चारों ओर अनुकूलित कर सकते हैं। sed के कुछ संस्करणों को निर्दिष्ट आदेशों की संख्या पर ऊपरी सीमाएं हैं; यदि यह एक समस्या है क्योंकि आपकी शब्द सूचियां काफी बड़ी हैं, तो आपको उत्पन्न जेनरेट स्क्रिप्ट को अलग-अलग फ़ाइलों में विभाजित करना पड़ सकता है जो लागू होते हैं - या सीमा के बिना कुछ उपयोग करने के लिए बदलें (उदाहरण के लिए पर्ल, उदाहरण के लिए)।

अन्य वस्तुओं के बारे में पता होना चाहिए परिवर्तनों का अनुक्रम है। यदि आप दो शब्दों को स्वैप करना चाहते हैं, तो आपको अपनी शब्द सूचियों को ध्यान से तैयार करने की आवश्यकता है। आम तौर पर, यदि आप wordB (1) wordA को wordB और (2) wordB से wordC को मैप करते हैं, तो यह मायने रखता है कि क्या स्क्रिप्ट स्क्रिप्ट मैपिंग (2) से पहले या बाद में मैपिंग (1) करता है।

दिखाया गया स्क्रिप्ट शब्द सीमाओं के बारे में सावधान नहीं है; sed के संस्करण के आधार पर आप इसका उपयोग कर रहे हैं और एक शब्द का गठन करने के लिए आपके मानदंडों के आधार पर, आप विभिन्न तरीकों से उनके बारे में सावधान रह सकते हैं।

+0

बी में एक शब्द की पूरी समस्या या आंशिक रूप से ए में होने की संभावित समस्या भी है। एक सच्चे समाधान के लिए शायद शब्दों में इनपुट तोड़ने और उन्हें एक बार बदलने की आवश्यकता होगी। – lhf

+0

यह त्रुटि उत्पन्न करता है: $ paste -d: listA listB | sed's/\ ([^:] * \): \ ([^:] * \)/s% \ 1% \ 2% '> sed।स्क्रिप्ट sed: -e अभिव्यक्ति # 1, चार 30: समाप्त नहीं 's 'कमांड – user248237dfsf

+0

@user, कि तय की। –

1

यह Tcl के साथ काफी सरल है शामिल नहीं है:

set fA [open listA r] 
set fB [open listB r] 
set fin [open input.file r] 
set fout [open output.file w] 

# read listA and listB and create the mapping of corresponding lines 
while {[gets $fA strA] != -1} { 
    set strB [gets $fB] 
    lappend map $strA $strB 
} 

# apply the mapping to the input file 
puts $fout [string map $map [read $fin]] 

# if the file is large, do it line by line instead 
#while {[gets $fin line] != -1} { 
# puts $fout [string map $map $line] 
#} 

close $fA 
close $fB 
close $fin 
close $fout 

file rename output.file input.file 
+0

+1 Tcl के इस्तेमाल के लिए बनाए रखने के लिए पर्ल में फिर से लिखने! –

1

आप bash में ऐसा कर सकते हैं। अपनी सूचियों को सरणी में प्राप्त करें।

listA=(a b c) 
listB=(d e f) 
data=$(<file) 
echo "${data//${listA[2]}/${listB[2]}}" #change the 3rd element. Redirect to file where necessary 
-1

उपयोग टीआर (1) (अनुवाद या वर्णों को हटाने):

cat file | tr 'abc' 'XYZ' > file_new 
mv file_new file 
+1

वह पूरे तारों को प्रतिस्थापित करना चाहता है व्यक्तिगत वर्ण –

2

मैं इसी तरह कुछ करने के लिए की जरूरत है, और मैं एक मानचित्र फ़ाइल पर आधारित एसईडी आदेशों पैदा समापन:

$ cat file.map 
abc => 123 
def => 456 
ghi => 789 

$ cat stuff.txt 
abc jdy kdt 
kdb def gbk 
qng pbf ghi 
non non non 
try one abc 

$ sed `cat file.map | awk '{print "-e s/"$1"/"$3"/"}'`<<<"`cat stuff.txt`" 
123 jdy kdt 
kdb 456 gbk 
qng pbf 789 
non non non 
try one 123 

सुनिश्चित करें कि आपका खोल आपके मानचित्र में जैसा कि sed के लिए कई पैरामीटर का समर्थन करता है।

+0

सुंदर एक-लाइनर !! – once

+0

शुद्ध 'sed' और' bash' संस्करण: '-f <(sed 's/=> // sed की # #/# की # $ #/# की #^# s/# 'file.map) stuff.txt'। – agc

संबंधित मुद्दे

 संबंधित मुद्दे