Reputation: 370
Here is the contents of a target.txt file:
line1
line2
Environment=xLink=https://11111/route
line4
line5
I am trying to write a bash script that will find the number of the line containing 'https' and then replace this entire line with a new string variable obtained within the bash script, here is the bash script without the replacement line:
#!/bin/bash
x="12345"
route="/route"
x_route="${x}${route}"
x_init="Environment=xLink=https://"
new_line="${x_init}${x_route}"
echo "${new_line}"
to_replace_line_number=$(find target.txt -type f | xargs grep -n 'https' | cut -c1-2)
echo "${to_replace_line_number}"
targetfile=target.txt
echo "${targetfile}"
Invoking this script outputs the following as expected:
Environment=xLink=https://12345/route
3:
target.txt
Now, without the bash script, if I invoked:
sudo sed -i '3 c\Environment=xLink=https://12345/route' target.txt
The target.txt changes as desired to:
line1
line2
Environment=xLink=https://12345/route
line4
line5
But the goal is to automate, so I am trying to use sed command to do the job inside the bash script. So far I tried two methods, none of them worked.
Method 1: I added the following line to the bash script:
sudo sed -i "${to_replace_line_number}s/.*/${new_line}/" ${targetfile}
When I ran the script, it didn't work and I got this error:
sed: -e expression #1, char 2: : doesn't want any addresses
Method 2: I added the following command to the bash script:
sudo sed -i "${to_replace_line_number} c\${new_line}" ${targetfile}
When I ran the script, it didn't work and I got this error:
sed: -e expression #1, char 2: : doesn't want any addresses
What is that I am missing exactly? Any help is very much appreciated.
Upvotes: 0
Views: 3012
Reputation: 35336
There are a couple issues with the current code:
to_replace_line_number
== 3:
- NOTICE the colon (:
); this is fed into the sed
command like such: sed -i "3: c\....
and is generating the error message stating an issue with the 2nd character, ie, the :
c\
option requires an escape character and an embedded carriage return ... or ...Minimal changes to OPs current code:
# parse the `grep -n` by having `cut` pull everthing before the (first) `:`
$ to_replace_line_number=$(find target.txt -type f | xargs grep -n 'https' | cut -d":" -f1)
$ echo "${to_replace_line_number}"
3
# modification to @thatotherguy's `sed/c` suggestion to allow all code to go on a single line:
$ sed -i -e "${to_replace_line_number} c\\" -e "${new_line}" ${targetfile}
$ cat "${targetfile}"
line1
line2
Environment=xLink=https://12345/route
line4
line5
Instead of spawning the sub-process calls to get the line number, there are several ways sed
can be used to find and replace the desired line.
One sed
idea:
sed -i "s|^.*https.*$|${new_line}|" ${targetfile}
Where:
|
- use pipe as sed
delimiter since ${new_line}
contains forward slashes^.*https.*$
- match any line that contains the string https
${new_line}
- replace the line with the contents of ${new_line}
After running the above:
$ cat target.txt
line1
line2
Environment=xLink=https://12345/route
line4
line5
Upvotes: 2
Reputation: 123650
\
is a special character, so when you use it in double quotes you have to escape it:
# Set example values and create a test file:
to_replace_line_number="3"
new_line="Environment=xLink=https://12345/route"
targetfile="test.txt"
printf 'line%d\n' {1..5} > "$targetfile"
# The actual command
sudo sed -i "${to_replace_line_number} c\\${new_line}" "${targetfile}"
This would make it equivalent to your manual invocation.
If you have wondered why the documentation for c
appears to be weirdly formatted compared to r
or y
, it's because the linefeed after the \
is intentional. This is the POSIX way of doing it:
sudo sed -i "${to_replace_line_number} c\\
${new_line}" "${targetfile}"
Upvotes: 2
Reputation: 66
This is because you are taking out two characters when reading the line number.As a result, an extra ':' is popping up in the variable. Instead, take out only the one field and it should work fine.
Replace
to_replace_line_number=$(find target.txt -type f | xargs grep -n 'https' | cut -c1-2)
with
to_replace_line_number=$(find target.txt -type f | xargs grep -n 'https' | cut -c1)
Upvotes: 3