लाइन नंबर द्वारा टेक्स्ट फाइल में पूरी लाइन कैसे बदलें


152

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

मैं उस लाइन में कुछ उप-स्ट्रिंग को बदलने की कोशिश नहीं कर रहा हूं, मैं बस उस लाइन को पूरी तरह से एक नई लाइन के साथ बदलना चाहता हूं।

क्या इसे करने के लिए कोई बैश तरीके हैं (या कुछ सरल जिसे एक .sh स्क्रिप्ट में डाला जा सकता है)।

जवाबों:


228

सबसे बड़ा नहीं है, लेकिन यह काम करना चाहिए:

sed -i 'Ns/.*/replacement-line/' file.txt

जहां Nआपके लक्ष्य लाइन नंबर द्वारा प्रतिस्थापित किया जाना चाहिए। यह मूल फ़ाइल में लाइन को बदल देता है। किसी भिन्न फ़ाइल में परिवर्तित पाठ को बचाने के लिए, -iविकल्प छोड़ें :

sed 'Ns/.*/replacement-line/' file.txt > new_file.txt

1
क्या स्क्रीन पर डंपिंग के बजाय फ़ाइल को संशोधित करने के लिए sed बनाने का कोई तरीका है?
user788171

8
मेरे लिए यह कहता है: sed: -e expression #1, char 26: unknown option to ``s'और मेरी लाइन है sed -i '7s/.*/<param-value>http://localhost:8080/ASDF/services/REWS.REWSHttpSoap12Endpoint/</param-value>/' $TCE_SVN_HOME\trunk\tce\EWC\WebContent\WEB-INF\web.xml:। कोई उपाय?
डेनजेल

4
/प्रतिस्थापन पाठ में प्रत्येक को sकमांड के समापन स्लैश के रूप में व्याख्या किया जाएगा जब तक कि वह बच न जाए ( \/)। हालांकि, सबसे आसान काम यह है कि सीमांकक के रूप में एक अलग, अप्रयुक्त चरित्र चुनना है। उदाहरण के लिए, sed -i '7s{.*}{<param-value>http://...}' $TCE_SVN_HOME/trunk...
१२:०३ पर शेपनर

4
यह स्पष्टीकरण थोड़ा भ्रमित करने वाला है और काम नहीं करता है। यदि आप लोगों को सीड और इसकी सीमांकक सेटिंग क्षमताओं के साथ समस्या है, तो आप इस पर एक नज़र रखना चाहते हैं: grymoire.com/Unix/Sed.html#uh-2 यह कहता है sकि सीमांकक के पीछे पहला चरित्र है। तो उदाहरण के लिए उपयोग करने के लिए अपनी कमांड को बदलने के लिए #यह इस तरह होगा:sed -i '7s#.*#<param-value>http://localhost:8080/ASDF/services/REWS.REWSHttpSoap12Endpo‌​int/</param-value>#'
func0der

7
@ Meonlol's पर विस्तार करने के लिए, macOS के लिए -eयदि आवश्यक हो -i, साथ ही दिया गया है; इस प्रकार, सही कमांड बन जाता है:sed -e 'Ns/.*/replacement-line/' -i '' file.txt
ELLIOTTCABLE

44

मैं वास्तव में हमारी कंपनी के UNIX सर्वर पर थोड़ी देर में क्रोन फ़ाइल में कोड की एक पंक्ति को बदलने के लिए इस स्क्रिप्ट का उपयोग करता था। हमने इसे सामान्य शेल स्क्रिप्ट के रूप में निष्पादित किया और इसमें कोई समस्या नहीं थी:

#Create temporary file with new line in place
cat /dir/file | sed -e "s/the_original_line/the_new_line/" > /dir/temp_file
#Copy the new file over the original file
mv /dir/temp_file /dir/file

यह लाइन नंबर से नहीं जाता है, लेकिन आप लाइन नंबर पर आधारित सिस्टम को आसानी से स्विच कर सकते हैं और लाइन s/वाइल्डकार्ड को जगह से पहले और वाइल्डकार्ड लगा सकते हैं the_original_line


17
बिल्ली का बेकार उपयोग:sed -e "s/.../.../" /dir/file > /dir/temp_file
Chepner

24
दुभाषिया / संकलक के लिए बेकार, लेकिन शायद इसे पढ़ने वाले मानव के लिए नहीं। @ काइल का कोड अच्छी तरह से बाएं से दाएं पढ़ा जाता है; संज्ञा से पहले क्रिया इस तथ्य के कारण है कि आपने मुहावरे का इस्तेमाल किया था, आइएमओ नहीं करता है।
क्लेटन स्टेनली

1
क्या उन दो पंक्तियों को मर्ज करने का एक तरीका है, उदाहरण के लिए कुछ इस तरह से,sed -e "s/.../.../" /dir/file > /dir/file
पबदु डोडांगोडा

22

मान लें कि आप पंक्ति 4 को "भिन्न" पाठ से बदलना चाहते हैं। आप AWK का उपयोग इस तरह कर सकते हैं:

awk '{ if (NR == 4) print "different"; else print $0}' input_file.txt > output_file.txt

AWK इनपुट को "रिकॉर्ड" मानता है जिसे "फ़ील्ड" में विभाजित किया गया है। डिफ़ॉल्ट रूप से, एक पंक्ति एक रिकॉर्ड है। NRदेखे गए रिकॉर्ड की संख्या है। $0वर्तमान पूर्ण रिकॉर्ड का प्रतिनिधित्व करता है (जबकि रिकॉर्ड $1से पहला क्षेत्र है और इसी तरह; डिफ़ॉल्ट रूप से फ़ील्ड लाइन से शब्द हैं)।

इसलिए, यदि वर्तमान लाइन संख्या 4 है, तो स्ट्रिंग को "अलग" प्रिंट करें, लेकिन अन्यथा अपरिवर्तित लाइन को प्रिंट करें।

AWK में, प्रोग्राम कोड { }प्रत्येक इनपुट रिकॉर्ड पर एक बार रन में संलग्न होता है ।

आपको शेल जैसी चीजों की व्याख्या करने की कोशिश से शेल को रखने के लिए एकल-उद्धरण में AWK कार्यक्रम को उद्धृत करने की आवश्यकता है $0

संपादित करें: नीचे दिए गए टिप्पणियों में @chepner से एक छोटा और अधिक सुंदर AWK कार्यक्रम:

awk 'NR==4 {$0="different"} { print }' input_file.txt

केवल रिकॉर्ड (यानी लाइन) नंबर 4 के लिए, पूरे रिकॉर्ड को "अलग" स्ट्रिंग के साथ बदलें। फिर हर इनपुट रिकॉर्ड के लिए, रिकॉर्ड प्रिंट करें।

स्पष्ट रूप से मेरे AWK कौशल जंग खाए हुए हैं! साभार, @chepner

संपादित करें: और @ डेनिस विलियमसन से भी छोटा संस्करण देखें:

awk 'NR==4 {$0="different"} 1' input_file.txt

टिप्पणियों में यह कैसे समझाया जाता है: 1हमेशा सही का मूल्यांकन होता है, इसलिए संबंधित कोड ब्लॉक हमेशा चलता रहता है। लेकिन कोई संबद्ध कोड ब्लॉक नहीं है, जिसका अर्थ है कि AWK पूरी लाइन को प्रिंट करने की अपनी डिफ़ॉल्ट कार्रवाई करता है। AWK को इस तरह के कार्यक्रमों की अनुमति देने के लिए बनाया गया है।


3
थोड़ा छोटा awk 'NR==4 {$0="different"} { print }' input_file.txt:।
Chepner

2
@chepner: थोड़ा छोटा:awk 'NR==4 {$0="different"}1' input_file.txt
अगली सूचना तक रुका हुआ।

@ डेनिसविलियम्सन, मुझे यह भी नहीं पता कि यह कैसे काम करता है! वह अनुगामी क्या करता है 1? (नोट: मैंने इसका परीक्षण किया है और यह वास्तव में काम करता है! मैं अभी समझ नहीं पा रहा हूं।)
स्टीवेहा

1
मुझे लगा कि बिना शर्त प्रिंट संक्षिप्त करने का एक तरीका होगा! @ जल्दवाहा: 1 केवल एक सही मूल्य है, जिसका अर्थ है एक "पैटर्न" जो हमेशा मेल खाता है। और एक मैच के लिए डिफ़ॉल्ट क्रिया वर्तमान लाइन को प्रिंट करना है।
चेंपर्स

19

इस परीक्षण फ़ाइल को दिया (test.txt)

Lorem ipsum dolor sit amet,
consectetur adipiscing elit. 
Duis eu diam non tortor laoreet 
bibendum vitae et tellus.

निम्न कमांड पहली पंक्ति को "न्यूलाइन टेक्स्ट" में बदल देगा

$ sed '1 c\
> newline text' test.txt

परिणाम:

newline text
consectetur adipiscing elit. 
Duis eu diam non tortor laoreet 
bibendum vitae et tellus.

अधिक जानकारी यहां पाई जा सकती है

http://www.thegeekstuff.com/2009/11/unix-sed-tutorial-append-insert-replace-and-count-file-lines/


2
यह सही उत्तर होना चाहिए। सी ध्वज ठीक वही करता है जो आवश्यक है (दिए गए पाठ के साथ एक क्रमांकित पंक्ति को प्रतिस्थापित करता है)।
एडेलफस

सीड के साथ वैकल्पिक वाक्यविन्यास जो
स्टडआउट

यह सही उत्तर है, लेकिन बदसूरत रेखा क्यों टूटती है? sed '1 cnewline text' test.txtयह भी करना होगा।
देव-नल

7

bash में, N, M को लाइन नंबर्स और xxx yyy से बदलें जो आप चाहते हैं

i=1
while read line;do
  if((i==N));then
    echo 'xxx'
  elif((i==M));then
    echo 'yyy'
  else
    echo "$line"
  fi
  ((i++))
done  < orig-file > new-file

संपादित करें

वास्तव में इस समाधान में "\ 0" "\ t" और "\" वर्णों के साथ कुछ समस्याएं हैं

"t", IFS = को पढ़ने से पहले हल किया जा सकता है: "\", -r के साथ पंक्ति के अंत में

IFS= read -r line

लेकिन "\ 0" के लिए, चर को काट दिया जाता है, शुद्ध बैश में कोई समाधान नहीं है: बैश में एक चर के लिए null-character (\ 0) युक्त स्ट्रिंग असाइन करें लेकिन सामान्य पाठ फ़ाइल में कोई nul character \ 0 नहीं है

पर्ल एक बेहतर विकल्प होगा

perl -ne 'if($.==N){print"xxx\n"}elsif($.==M){print"yyy\n"}else{print}' < orig-file > new-file

मैंने शुद्ध BASH समाधान के लिए प्रयास करने के बारे में भी नहीं सोचा था!
स्टीवेहा

4
# Replace the line of the given line number with the given replacement in the given file.
function replace-line-in-file() {
    local file="$1"
    local line_num="$2"
    local replacement="$3"

    # Escape backslash, forward slash and ampersand for use as a sed replacement.
    replacement_escaped=$( echo "$replacement" | sed -e 's/[\/&]/\\&/g' )

    sed -i "${line_num}s/.*/$replacement_escaped/" "$file"
}

3

चेपनेर से उत्कृष्ट जवाब। यह मेरे लिए बैश शेल में काम कर रहा है।

 # To update/replace the new line string value with the exiting line of the file
 MyFile=/tmp/ps_checkdb.flag

 `sed -i "${index}s/.*/${newLine}/" $MyFile`

यहां
index- लाइन नंबर
newLine- नई लाइन स्ट्रिंग जिसे हम बदलना चाहते हैं।


इसी प्रकार फ़ाइल में किसी विशेष लाइन को पढ़ने के लिए नीचे दिए गए कोड का उपयोग किया जाता है। यह वास्तविक फ़ाइल को प्रभावित नहीं करेगा।

LineString=`sed "$index!d" $MyFile` 

यहां
!d- लाइन नं। के अलावा अन्य लाइनों को हटा देगा $index ताकि हम आउटपुट को $indexफाइल में बिना नंबर के लाइन स्ट्रिंग के रूप में प्राप्त करें ।


लेकिन यह मेरी मार है कि परिणाम केवल क्यों दिखाता है ${newline}?
साइकिसिस

1

मैक पर मैंने इस्तेमाल किया

sed -i '' -e 's/text-on-line-to-be-changed.*/text-to-replace-the=whole-line/' file-name

-2

आप sed कमांड में पैरामीटर भी पास कर सकते हैं:

test.sh

#!/bin/bash
echo "-> start"
for i in $(seq 5); do
  # passing parameters to sed
  j=$(($i+3))
  sed -i "${j}s/.*/replaced by '$i'!/" output.dat
done
echo "-> finished"
exit 

orignial output.dat:

a
b
c
d
e
f
g
h
i
j

निष्पादन ./test.sh नया आउटपुट देता है

a
b
c
replaced by '1'!
replaced by '2'!
replaced by '3'!
replaced by '4'!
replaced by '5'!
i
j

1
आपको इस उदाहरण के लिए लूप की आवश्यकता क्यों है, बस समाधान को बाधित करता है? line=5; sed -i "${line}s/.*/replaced by '$i'!/" output.dat
रोब

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