Reputation: 97
data.txt file :
Roll no : 65
Name : Abc
Roll no : 67
Name : Pqr
Roll no : 68
Name : Xyz
Now, I want to take Roll no as input from user and then replace the old name with new name
sed -i -e 's/'$tmproll'/{'$tmpName';s/\n.*//;}' $filename
sed -i -e 's/'$tmproll'/'$tmpName'/{N;s/\n.*//;}' $filename
Expected Result :
Enter the Roll no to modify : 65
Enter new Name for that Roll no : Mno
Then data.txt file :
Roll no : 65
Name : Mno
Roll no : 67
Name : Pqr
Roll no : 68
Name : Xyz
My actual output
Enter the Roll no to modify : 65
Enter new Name for that Roll no : Mno
sed: -e expression #1, char 17: unknown option to `s'
Upvotes: 0
Views: 131
Reputation: 189377
This looks like you erroneously put an s
before the first slash. s/regex/replacement/
replaces matches of regex
with the text replacement
, whereas just /regex/
is an address expression which selects lines which match regex
.
You also put the replacement in a weird place, but your second attempt looks fixable with fairly minor changes. Try
sed -i -e '/'"$tmproll"'/{N;s/\n.*/\nName: '"$tmpName"'/;}' "$filename"
Notice also the quoting fixes; see also When to wrap quotes around a shell variable? (the quoting could actually be simplified quite a bit by switching to double quotes altogether).
In more detail, a sed
script consists of a sequence of address command pairs. The address is optional; in its absence, the command is applied to every input line. This script contains the commands N
(fetch the next input line, so that the pattern space contains both the original line and the following one, separated by a newline character) and s/regex/replacement/
to replace the text after the newline character (i.e. the new line we fetched with N
) with new text. The commands are inside braces to say they all should be applied if the address expression matched.
Using sed
for any non-trivial logic tends to produce write-only scripts; this would arguably be easier to write and understand in Awk.
awk -v no="$tmproll" -v name="$tmpName" '/Roll no / && $4 == no { replace=1 }
/Name / && replace { $3=name }1' "$filename"
You will need to write the result to a temporary file and then rename it if you don't have GNU Awk, which has an inplace
facility similar to sed -i
.
Upvotes: 0
Reputation: 97
I don't think that it the right way to do this but I have come up with a solution. So first we'll try to find the line number of the Roll no in the file,then wel'll increment it by one,since our Name comes after Roll no. Then we'll replace that line with the desired Name that we want. Here's the code for it :
Data.txt before modification
Roll no : 65
Name : ABC
Roll no : 66
Name : DEF
Roll no : 67
Name : MNO
#CODE STARTS FROM HERE
echo -n "Enter the Roll no to modify : "
read tmproll
if grep -q $tmproll "$filename"; then
lineno=$(sed -n -e '/'$tmproll'/=' $filename)
lineno=$((lineno+1));
echo -n "Enter the new Name : "
read tmpName
sed -i -e "$lineno c\Name : $tmpName" $filename
fi
#CODE ENDS HERE
Data.txt after this code
Roll no : 65
Name : ABC
Roll no : 66
Name : DEF
Roll no : 67
Name : PQR
Upvotes: 0
Reputation: 52344
As an alternative to using sed for in-place editing, you might consider ed
, of all things (It's actually quite useful for simple editing of files in a script).
Demonstration script:
#!/bin/sh
tmproll=65
tmpname=Mno
ed -s data.txt <<EOF
/^Roll no[[:space:]]*:[[:space:]]*${tmproll}$/+1 s/:.*/: ${tmpname}/
w
EOF
It looks for a line matching the desired roll number (The leading /regex/
), and on the line after it (+1
), replaces everything after the colon with the new name (The s///
). Then it saves the file (w
).
Example:
$ cat data.txt
Roll no : 65
Name : Abc
Roll no : 67
Name : Pqr
Roll no : 68
Name : Xyz
$ sh example.sh
$ cat data.txt
Roll no : 65
Name : Mno
Roll no : 67
Name : Pqr
Roll no : 68
Name : Xyz
Upvotes: 1