एक पैटर्न बदलने के लिए एक स्ट्रिंग से बच


317

मेरी बैश स्क्रिप्ट में मेरे पास एक बाहरी (उपयोगकर्ता से प्राप्त) स्ट्रिंग है, जिसे मुझे sed पैटर्न में उपयोग करना चाहिए।

REPLACE="<funny characters here>"
sed "s/KEYWORD/$REPLACE/g"

मैं $REPLACEस्ट्रिंग से कैसे बच सकता हूं, इसलिए इसे sedशाब्दिक प्रतिस्थापन के रूप में सुरक्षित रूप से स्वीकार किया जाएगा ।

नोट: यह KEYWORDएक गूंगा विकल्प है जिसका कोई मिलान नहीं है आदि। यह उपयोगकर्ता द्वारा आपूर्ति नहीं की जाती है।


13
क्या आप "लिटिल बॉबी टेबल्स" समस्या से बचने की कोशिश कर रहे हैं यदि वे "/ g -e 's / PASSWORD =। * / PASSWORD = abc / g'" कहते हैं?
पॉल टॉम्बलिन

2
यदि बैश का उपयोग कर रहे हैं, तो आपको sed की आवश्यकता नहीं है। बस का उपयोग करेंoutputvar="${inputvar//"$txt2replace"/"$txt2replacewith"}".
डेस्टेंसन

@destenson मुझे लगता है कि आपको उद्धरणों के बाहर दो चर नहीं लगाने चाहिए। बैश डबल-कोट्स के अंदर चर पढ़ सकते हैं (आपके उदाहरण में, व्हॉट्सएप चीजों को पेंच कर सकता है)।
कैमिलो मार्टिन

2
इसे भी देखें: stackoverflow.com/q/29613304/45375
mklement0

1
@CamiloMartin, मेरे जवाब पर मेरी टिप्पणी देखें। $ {} के अंदर के उद्धरण अंदर के उद्धरणों से मेल नहीं खाते हैं। दो चर उद्धरण के बाहर नहीं हैं ।
डेस्टेंसन

जवाबों:


268

चेतावनी : यह नई कहानियों पर विचार नहीं करता है। अधिक गहन उत्तर के लिए, इसके बजाय इस SO-प्रश्न को देखें । (धन्यवाद, एड मॉर्टन और निकल्स पीटर)

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

जैसा कि बेन ब्लैंक ने कहा, केवल तीन ही पात्र हैं जिन्हें प्रतिस्थापन स्ट्रिंग में भाग जाने की आवश्यकता है (स्वयं से बच जाता है, बयान के अंत के लिए आगे स्लैश और सभी को बदलने के लिए):

ESCAPED_REPLACE=$(echo $REPLACE | sed -e 's/[\/&]/\\&/g')
# Now you can use ESCAPED_REPLACE in the original sed statement
sed "s/KEYWORD/$ESCAPED_REPLACE/g"

यदि आपको कभी KEYWORDस्ट्रिंग से बचने की आवश्यकता है , तो निम्नलिखित वह है जो आपको चाहिए:

sed -e 's/[]\/$*.^[]/\\&/g'

और द्वारा उपयोग किया जा सकता है:

KEYWORD="The Keyword You Need";
ESCAPED_KEYWORD=$(echo $KEYWORD | sed -e 's/[]\/$*.^[]/\\&/g');

# Now you can use it inside the original sed statement to replace text
sed "s/$ESCAPED_KEYWORD/$ESCAPED_REPLACE/g"

याद रखें, यदि आप /सीमांकक के अलावा किसी अन्य पात्र का उपयोग करते हैं, तो आपको उन वर्णों के स्लेश को बदलने की आवश्यकता है, जो आपके द्वारा उपयोग किए जा रहे हैं। विवरण के लिए पीटरजेक्लॉ की टिप्पणी देखें।

संपादित: कुछ कोने के मामलों के कारण पहले के लिए जिम्मेदार नहीं हैं, ऊपर दिए गए आदेश कई बार बदल गए हैं। विवरण के लिए संपादित इतिहास जांचें।


17
यह ध्यान देने योग्य है कि आप सीमांकक के रूप में उपयोग न करके आगे की स्लैश से बचने से बच सकते हैं। अधिकांश (सभी?) Sed के संस्करण आपको किसी भी वर्ण का उपयोग करने की अनुमति देते हैं, इसलिए जब तक यह पैटर्न फिट नहीं होता है: $ गूंज 'फू / बार' | sed s _ / _: _ # foo: bar
PeterJCLaw

2
sed -e 's / (\ / \ / \\\ | &) / \\ & / g' ने OSX पर मेरे लिए काम नहीं किया लेकिन यह करता है: sed 's ((\\\ / &]) / \\ & / 'और यह थोड़ा छोटा है।
1

1
जीएनयूKEYWORD^$s/[]\/$*.^|[]/\\&/g
सेड

1
@ जेसे: फिक्स्ड। वास्तव में, यह वह गलती है जिसके बारे में मैंने पहले पैराग्राफ में चेतावनी दी थी। मुझे लगता है मैं अभ्यास नहीं करता कि मैं क्या उपदेश देता हूं।
पियानोसॉरस

1
@NeronLeVelu: मुझे यकीन नहीं है कि मुझे पता है कि आपका क्या मतलब है, लेकिन "पाइप या चर में कोई विशेष अर्थ नहीं है। परिणाम को चलाने से पहले शेल द्वारा इसे पार्स किया जाता है, इसलिए चर के अंदर दोहरे उद्धरण सुरक्षित हैं। उदाहरण के लिए, चल रहा है A='foo"bar' echo $A | sed s/$A/baz/। बैश। डबल कोट्स को 'फू' और 'बार' के समान माना जाता है।
पियानोसॉरस

92

सेड कमांड आपको /विभाजक के बजाय अन्य वर्णों का उपयोग करने की अनुमति देता है :

sed 's#"http://www\.fubar\.com"#URL_FUBAR#g'

डबल कोट्स कोई समस्या नहीं है।


5
आपको अभी भी भागने की ज़रूरत है .जो अन्यथा एक विशेष अर्थ रखता है। मैंने आपका उत्तर संपादित किया।
ypid

मैं बस करने की कोशिश की है sed '/CLIENTSCRIPT="foo"/a CLIENTSCRIPT2="hello"' fileके साथ sed '|CLIENTSCRIPT="foo"|a CLIENTSCRIPT2="hello"' fileकि और एक ही नहीं करता है।
दिमित्री कोपरीवा

1
क्योंकि यह केवल स्थानापन्न पर लागू होता है, यह कहा जाना चाहिए: ssed के कमांड (विकल्प के रूप में) आपको विभाजक के रूप में / के बजाय अन्य वर्णों का उपयोग करने की अनुमति देता है। इसके अलावा, यह एक उत्तर होगा कि स्लैश अक्षरों के साथ URL पर sed का उपयोग कैसे करें। यह ओपी सवाल का जवाब नहीं देता है कि किसी उपयोगकर्ता द्वारा दर्ज की गई स्ट्रिंग से कैसे बचना है, जिसमें /, \, लेकिन # भी शामिल हो सकता है यदि आप इसका उपयोग करने का निर्णय लेते हैं। और इसके अलावा, यूआरआई # भी शामिल कर सकते हैं
इनके

2
इसने मेरी जिंदगी बदल दी! धन्यवाद!
फ्रांसिसकॉन सैंटोस

48

केवल तीन शाब्दिक वर्ण जो विशेष रूप से प्रतिस्थापित खंड में व्यवहार किए जाते हैं /( खंड को बंद करने के लिए), \(वर्णों से बचने के लिए, पीछे हटना और सी), और &(प्रतिस्थापन में मैच को शामिल करने के लिए)। इसलिए, आपको केवल उन तीन पात्रों से बचना है:

sed "s/KEYWORD/$(echo $REPLACE | sed -e 's/\\/\\\\/g; s/\//\\\//g; s/&/\\\&/g')/g"

उदाहरण:

$ export REPLACE="'\"|\\/><&!"
$ echo fooKEYWORDbar | sed "s/KEYWORD/$(echo $REPLACE | sed -e 's/\\/\\\\/g; s/\//\\\//g; s/&/\\\&/g')/g"
foo'"|\/><&!bar

इसके अलावा एक नई रूपरेखा, मुझे लगता है। मैं एक नई रेखा से कैसे बचूँ?
अलेक्जेंडर ग्लैडीश

2
बैकस्लैश के संबंध में गूंज का डिफ़ॉल्ट व्यवहार क्या है, इसके बारे में सावधान रहें। बैश में, इको डिफॉल्ट बैकस्लैश की कोई व्याख्या करने से चूक जाता है, जो यहां उद्देश्य को पूरा करता है। डैश (श) में, दूसरी ओर, इको इंटरप्रिट्स बैकस्लैश बच जाता है और इसका कोई तरीका नहीं है, जहां तक ​​मुझे पता है, इसे दबाने के लिए। इसलिए, डैश (श) में, प्रतिध्वनि $ x के बजाय, प्रिंट '% s \ n' $ x करें।
यूसुफ एल्डकर

साथ ही, उपयोगकर्ता इनपुट में शाब्दिक रूप में बैकस्लैश का इलाज करने के लिए रीड करते समय -r विकल्प का उपयोग करें।
यूसुफ एल्डाकर

अन्य गोले के साथ क्रॉस-प्लेटफ़ॉर्म संगतता के लिए, आपको इस दस्तावेज़ को sed विशेष वर्णों के प्रतिस्थापन के बारे में सलाह लेनी चाहिए: grymoire.com/Unix/Sed.html#toc-uh-62
Dejay Clayton

2
@ ड्रूक्स तीन अक्षर रिप्लेस क्लॉज में केवल विशेष हैं । पैटर्न क्लॉज में बहुत कुछ खास है।
lenz

33

पियानोसॉरस के नियमित भावों के आधार पर, मैंने एक बैश फ़ंक्शन बनाया जो कीवर्ड और प्रतिस्थापन दोनों से बच जाता है।

function sedeasy {
  sed -i "s/$(echo $1 | sed -e 's/\([[\/.*]\|\]\)/\\&/g')/$(echo $2 | sed -e 's/[\/&]/\\&/g')/g" $3
}

यहां बताया गया है कि आप इसका उपयोग कैसे करते हैं:

sedeasy "include /etc/nginx/conf.d/*" "include /apps/*/conf/nginx.conf" /etc/nginx/nginx.conf

3
धन्यवाद! अगर किसी और को इसका इस्तेमाल करते समय सिंटैक्स त्रुटि मिलती है, तो मेरी तरह, बस बैश का उपयोग करके इसे चलाने के लिए याद रखें, श नहीं
कोन्स्टेंटिन पेरियासालोव

1
वहाँ एक समारोह के लिए सिर्फ एक स्ट्रिंग से बचने के बजाय sed के आसपास लपेटने के बजाय है?
CMCDragonkai

अरे, इस तरह एक प्रतिध्वनि के साथ पाइप शुरू करने के बारे में सिर्फ एक सामान्य चेतावनी: कुछ (सबसे?) इको के कार्यान्वयन विकल्प लेते हैं (देखें man echo), जब आपके $1डैश से शुरू होने पर पाइप अप्रत्याशित रूप से व्यवहार करता है । इसके बजाय, आप अपने पाइप को इसके साथ शुरू कर सकते हैं printf '%s\n' "$1"
पियानोसॉरस

17

इसका जवाब देने में थोड़ा देर हो गई है ... लेकिन ऐसा करने का बहुत सरल तरीका है। बस सीमांकक बदलें (यानी, क्षेत्र को अलग करने वाला चरित्र)। इसलिए, s/foo/bar/आप के बजाय लिखें s|bar|foo

और, यहाँ यह करने का आसान तरीका है:

sed 's|/\*!50017 DEFINER=`snafu`@`localhost`\*/||g'

परिणामी उत्पादन उस बुरा DEFINER खंड से रहित है।


10
नहीं, &और `` अभी भी बच जाना चाहिए, जैसा कि परिसीमन, जो भी चुना जाता है।
मिराबिलोस

3
इससे मेरी समस्या हल हो गई, क्योंकि मेरे पास प्रतिस्थापन स्ट्रिंग में "/" वर्ण थे। धन्यवाद दोस्त!
एवगेनी गोल्डिन

मेरे लिये कार्य करता है। क्या कर रहा है $स्ट्रिंग में भागने के बारे में बदला जाने की कोशिश कर रहा है , और $प्रतिस्थापन स्ट्रिंग में अर्थ को बनाए रखना है । मैं $XXXचर के मूल्य में बदलाव करना चाहता हूं $YYY, sed -i "s|\$XXX|$YYY|g" fileठीक काम करता है।
हकुनामी

11

यह पता चला है कि आप गलत सवाल पूछ रहे हैं। मैंने भी गलत सवाल पूछा। इसका कारण गलत है पहले वाक्य की शुरुआत: "मेरी बैश स्क्रिप्ट में ..."।

मेरा एक ही सवाल था और वही गलती। यदि आप बैश का उपयोग कर रहे हैं, तो आपको स्ट्रिंग रिप्लेसमेंट करने के लिए sed का उपयोग करने की आवश्यकता नहीं है (और यह बैश में निर्मित रिप्लेसमेंट फीचर का उपयोग करने के लिए बहुत क्लीनर है)।

उदाहरण के लिए, जैसे कुछ के बजाय:

function escape-all-funny-characters() { UNKNOWN_CODE_THAT_ANSWERS_THE_QUESTION_YOU_ASKED; }
INPUT='some long string with KEYWORD that need replacing KEYWORD.'
A="$(escape-all-funny-characters 'KEYWORD')"
B="$(escape-all-funny-characters '<funny characters here>')"
OUTPUT="$(sed "s/$A/$B/g" <<<"$INPUT")"

आप विशेष रूप से बैश सुविधाओं का उपयोग कर सकते हैं:

INPUT='some long string with KEYWORD that need replacing KEYWORD.'
A='KEYWORD'
B='<funny characters here>'
OUTPUT="${INPUT//"$A"/"$B"}"

BTW, सिंटैक्स हाइलाइटिंग यहाँ गलत है। बाहरी उद्धरण मेल खाते हैं और आंतरिक उद्धरण मेल खाते हैं। दूसरे शब्दों में, यह दिखता है $Aऔर $Bअयोग्य है, लेकिन वे नहीं हैं। अंदर के ${}उद्धरण उसके बाहर के उद्धरणों से मेल नहीं खाते।

आपको वास्तव में एक असाइनमेंट के दाहिने हाथ की ओर उद्धृत नहीं करना है (जब तक कि आप ऐसा कुछ नहीं करना चाहते हैं var='has space') - OUTPUT=${INPUT//"$A"/"$B"}सुरक्षित है।
बेंजामिन डब्ल्यू।

आपको वास्तव में एक असाइनमेंट के राइट-साइड साइड को उद्धृत करने की ज़रूरत नहीं है (जब तक कि आप इसे वास्तविक दुनिया में काम नहीं करना चाहते हैं और न ही खिलौना स्क्रिप्ट के रूप में युर पागल स्किल्ज़ दिखाना है)। मैं हमेशा प्रत्येक चर विस्तार को उद्धृत करने की कोशिश करता हूं जो मैं नहीं चाहता कि शेल की व्याख्या हो, जब तक कि मेरे पास कोई विशिष्ट कारण न हो। इस तरह, चीजें कम अक्सर टूटती हैं, खासकर जब नए या अप्रत्याशित इनपुट के साथ प्रदान की जाती हैं।
२०:४ '

1
मैनुअल देखें : "सभी मान टिल्ड विस्तार, पैरामीटर और चर विस्तार, कमांड प्रतिस्थापन, अंकगणितीय विस्तार और उद्धरण हटाने (नीचे विस्तृत) से गुजरते हैं।" यानी, दोहरे उद्धरण चिह्नों के समान।
बेंजामिन डब्ल्यू।

1
यदि आपको किसी फ़ाइल पर sed का उपयोग करने की आवश्यकता हो तो क्या होगा?
एफ्रेन

1

Awk का उपयोग करें - यह क्लीनर है:

$ awk -v R='//addr:\\file' '{ sub("THIS", R, $0); print $0 }' <<< "http://file:\_THIS_/path/to/a/file\\is\\\a\\ nightmare"
http://file:\_//addr:\file_/path/to/a/file\\is\\\a\\ nightmare

2
इसके साथ परेशानी awkयह है कि इसके समान कुछ भी नहीं है sed -i, जो कि 99% समय के लिए बेहद आसान है।
टीनो

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

0

यहां एक AWK का एक उदाहरण है जिसका मैंने कुछ समय पहले इस्तेमाल किया था। यह एक AWK है जो नए AWKS को प्रिंट करता है। AWK और SED समान होने के कारण यह एक अच्छा खाका हो सकता है।

ls | awk '{ print "awk " "'"'"'"  " {print $1,$2,$3} " "'"'"'"  " " $1 ".old_ext > " $1 ".new_ext"  }' > for_the_birds

यह अत्यधिक दिखता है, लेकिन किसी भी तरह उद्धरणों का संयोजन शाब्दिक रूप से मुद्रित करने के लिए काम करता है। फिर अगर मुझे सही ढंग से याद है कि वैबल्स सिर्फ इस तरह से उद्धरण के साथ घिरे हैं: "$ 1"। यह कोशिश करो, मुझे बताएं कि यह SED के साथ कैसे काम करता है।


0

मेरे पास सेडसी फ़ंक्शन पर सुधार है, जो टैब जैसे विशेष पात्रों के साथ टूट जाएगा।

function sedeasy_improved {
    sed -i "s/$(
        echo "$1" | sed -e 's/\([[\/.*]\|\]\)/\\&/g' 
            | sed -e 's:\t:\\t:g'
    )/$(
        echo "$2" | sed -e 's/[\/&]/\\&/g' 
            | sed -e 's:\t:\\t:g'
    )/g" "$3"
}

तो, क्या अलग है? $1और $2खोल विस्तार और टैब या दोहरे स्थानों को संरक्षित करने के लिए कोट में लिपटे।

अतिरिक्त पाइपिंग | sed -e 's:\t:\\t:g'(मुझे :टोकन पसंद है ) जो एक टैब को अंदर बदल देता है \t


लेकिन पाइपों में प्रतिध्वनि का उपयोग करने के बारे में सरल जवाब पर मेरी टिप्पणी देखें।
पियानोसॉरस

0

ये भागने के कोड हैं जो मैंने पाया है:

* = \x2a
( = \x28
) = \x29

" = \x22
/ = \x2f
\ = \x5c

' = \x27
? = \x3f
% = \x25
^ = \x5e

-1

सभी आनंद को मत भूलो जो आस-पास के खोल के साथ होता है "और '

तो (ksh में)

Var=">New version of \"content' here <"
printf "%s" "${Var}" | sed "s/[&\/\\\\*\\"']/\\&/g' | read -r EscVar

echo "Here is your \"text\" to change" | sed "s/text/${EscVar}/g"

वास्तव में जिस दिशा की मुझे आवश्यकता थी, उसके परिणाम खोजने के लिए, जो Google के माध्यम से मिली, वह किसी के लिए सहायक हो सकती है - जिसके साथ समाप्त हुआ - sed "s / [/ \\\ * \\" \ "\" ") () / \\ & / g '
मोलबोर्ग

-1

अगर आप अभी sed कमांड में Variable value को बदलना चाहते हैं तो अभी उदाहरण निकालें:

sed -i 's/dev-/dev-$ENV/g' test to sed -i s/dev-/dev-$ENV/g test

-2

यदि मामला ऐसा होता है कि आप sedपैटर्न बदलने के लिए पास होने के लिए एक यादृच्छिक पासवर्ड उत्पन्न कर रहे हैं , तो आप सावधान रहना चुनते हैं कि यादृच्छिक स्ट्रिंग में अक्षरों का कौन सा सेट है। यदि आप किसी मान को बेस 64 द्वारा एन्कोडिंग करके बनाया गया पासवर्ड चुनते हैं, तो केवल वही चरित्र है जो बेस 64 में दोनों संभव है और बदले हुए sedपैटर्न में भी एक विशेष चरित्र है । वह चरित्र "/" है, और आपके द्वारा उत्पन्न पासवर्ड से आसानी से हटा दिया जाता है:

# password 32 characters log, minus any copies of the "/" character.
pass=`openssl rand -base64 32 | sed -e 's/\///g'`;

-4

ऐसा करने का एक आसान तरीका केवल हाथ से पहले स्ट्रिंग का निर्माण करना है और इसे एक पैरामीटर के रूप में उपयोग करना है sed

rpstring="s/KEYWORD/$REPLACE/g"
sed -i $rpstring  test.txt

विफल और बेहद खतरनाक, जैसा कि REPLACE उपयोगकर्ता की आपूर्ति करता है: REPLACE=/देता हैsed: -e expression #1, char 12: unknown option to `s'
Tino
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.