sed giving error when I try to replace a string - bash

when I try to edit a yaml file, and replace the string after image :
I am doing this sed -i "s/\<image :\>/& bar/" test.yaml
where my test.yaml file has this
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "1"
creationTimestamp: "2019-11-19T22:42:10Z"
generation: 1
....
image: foo
want replace foo with bar
getting error
sed: -e expression #1, char 3: unterminated `s' command
this is the error I am getting

In sed, you can't put a forwardslash / before the substitution command s. The correct syntax is s/regexp/replacement/ or simply s/old/new/.
When you execute sed like you did with sed -i "/s/\<image :\>/& bar/", it will expect a builtin command after the second / such as sed -i /regexp/command or sed -i /string/d to delete the line with the matched string. However, it find the \ character and stops because it isn't a sed command.

Related

Not able to add a line of text after pattern using sed in OSX

I'm trying to add a line in a file afile.xyz using my script. This is what I've done so far using sed:
n="$(grep ".method" "$m" | grep "onCreate(Landroid/os/Bundle;)V")"
sed -i '' -e '/$n/ a\
"test", /Users/username/Documents/afile.xyz
I'm getting the error:
"onCreate\(\Landroid\/ ...": bad flag in substitute command: 'g'
How do I solve this? Please do help. Thanks.
Edit: Content of n
method protected onCreate(Landroid/os/Bundle;)V
2 problems:
because the sed body is in single quotes, the variable $n will not be expanded,
the regular expression in $n contains the / dilimiters.
Try this:
n=$(...)
nn=${n//\//\\/} # escape all slashes
sed -i '' '/'"${nn}"'/ a ...
The single-quoted sed body is interrupted to append the double quoted shell variable.
You can also use a different delimiter for the RE:
sed -i '' -e "\#$n# a\\
\"test\"" /Users/username/Documents/afile.xyz

Replace a value in yaml file with multi line string using sed

I have been trying to replace/add value of a field in yaml with an env variable that has multi line string, using below syntax
replacewith=" |-
multi
line
string"
sed -i -e "s/^\(\s*key-in-yaml\s*:\s*\).*/\1 $replacewith/" somefile.yaml
We can assume that key-in-yaml doesn't have any value by default. Above comand results in
sed: -e expression #1, char 37: unterminated `s' command
I also want the indentation to be maintained.
If this is the content of yaml file
apiVersion: operators.coreos.com/v1alpha1
kind: ClusterServiceVersion
metadata:
annotations:
alm-examples:
capabilities: Basic Install
after that sed command i was expecting
apiVersion: operators.coreos.com/v1alpha1
kind: ClusterServiceVersion
metadata:
annotations:
alm-examples: |-
multi
line
string
capabilities: Basic Install
With your shown samples, please try following, in case you are ok with awk.
awk -v str="$replacewith" '
1;
/annotations:/{ found=1 }
found && /alm-examples: \|-/{
print str
found=""
}
' Input_file
Once you are happy with above results(which will be shown on terminal) and in case you want to save them into Input_file itself then append > temp && mv temp Input_file to above command.
sed -E '/alm-examples/s/(.*)$/printf "\1 $replacewith"/e' somefile.yaml
This uses s///e to shell out to printf which will handle the multiline string better than attempts to inline it with sed commands. It is printf expanding the string, not sed, because the sed command is in single quotes.
This also works, with & replacing the \1, because the line break doesn't get passed to printf either way:
sed -E '/alm-examples/s/.*/printf "& $replacewith"/e' somefile.yaml
Or, to depend on annotations: in the prior line:
sed -E '/annotations:/{N;/alm-examples/s/.*/printf "& $replacewith"/e}' somefile.yaml
I have decided to use yq and it has been working great even for complex fields in yaml for example a.b.c[0].d=env-var-multiline.

How to expand correctly a variable in sed command

I have this file:
user0:
hash: $2a$12$DA47ZutoC.89KDePyBK.yubz.2vfEiLi28ENBRuyoNf.px3.vHINq
user1:
hash: $2a$12$Auk82xqdbgFb4AJKyvSuWOKTQivuHhJZwckLii5/a5ILhCke0sddS
user3:
hash: $2a$12$QW/dCK7CqE5s87OIk8QBeeBYVvD5tjbd46jH9wVD9YMWW31KQEA1y
user4:
hash: $2a$12$60ds1ivJzM/DexIBYUilzO4BPjumsdTOETAHoopIxabffoWiDEkum
and a bash script to change the hash associated to a username.
For example to change user1 hash, i would use:
sed -i "/user1:/{n;s,.*, hash: NEW_HASH/}" MY_FILE
Now, in the script I have variables, and so actually my previous example is:
sed -i "/$1:/{n;s,.*, hash: $hash/}" "$users"
My problem is that the $hash parameter has got also / characters, resulting in a sed error like this:
sed: -e expression #1, char 85: unterminated `s' command
How to correct my command in order to let it expand hash variable correctly? I tried some combinations of ' and " commands but without results. Any help?
Thank you!
Since you are using , as the delimiter for the s command it should be:
sed -i "/$1:/{n;s,.*, hash: $hash,;}" "$users"
----------------------------------^ comma, not /
I've also appended a ; after the s command. Some implementations of sed need that.

Unable to define line number in sed by variable

I'm trying to use an array to define the lines to replace using sed; I can delete the lines using a variable for the line number but I can't get sed to use the variable to define the line number to write to. The problem seems to reside in the insert line. How do you pass the value of an array as a line number to sed?
#!/bin/bash
lineNum=$(sed -n '/max_allowed_packet/=' /etc/mysql/my.cnf)
IFS= #There's a space as the delimiter#
ary=($lineNum)
#for key in "${!ary[#]}";
# do
# sed -i '$ary[$key]'d /etc/mysql/my.cnf;
# #The folllowing line errors#
# sed -i "'$ary[$key]'imax_allowed_packet = 32M" /etc/mysql/my.cnf;
# #The above line errors#
#done
#for val in "${ary[#]}";
# do
# sed -i "${val}d" /etc/mysql/my.cnf;
# sed -i "${val}imax_allowed_packet = 32M" /etc/mysql/my.cnf;
# done
for val in "${ary[#]}";
do
sed -i "${val}s/.*/imax_allowed_packet = 32M" /etc/mysql/my.cnf";
done
For the first stanza of script I get the following output:
Error: sed: -e expression #1, char 1: unknown command: `''
For the second Stanza I get the following output:
sed: -e expression #1, char 3: unknown command:
'
sed: -e expression #1, char 3: unknown command:
'
For the third Stanza I get the following output:
./test.sh: line 22: unexpected EOF while looking for matching `"'
./test.sh: line 24: syntax error: unexpected end of file
Edit, rewriting the sed commands as sed -i "${ary[$key]}" generates the following error output: sed: -e expression #1, char 3: unknown command: `
I think you're over-complicating the issue. Your script can be reduced to this:
sed 's/\(max_allowed_packet\).*/\1 = 32M/' /etc/mysql.cnf
This performs a substitution on every occurrence of max_allowed_packet, setting the rest of the line to = 32M. Add the -i switch to overwrite the file when you're happy with the result.
Problems with your attempt
Shell parameters are not expanded within single quotes, so you would need to use double quotes, e.g. sed -i "${ary[$key]}d". You can use set -x to see what is happening here - at the moment, you will see the literal string $ary[$key], rather than the array value.
If I understand your intention correctly (you want to substitute the entire line), there's no need to call sed twice:
for val in "${ary[#]}"; do
sed -i.bak "${val}s/.*/imax_allowed_packet = 32M" /etc/mysql/my.cnf
done
I have chosen to loop through the values of the array, instead of the keys, in order to simplify things a little. When using the -i option, it is always a good idea to specify a backup file, as I have done.

ssh sed not changing variables correctly

I'm trying to use sed to change a variable in the site.js file on my server.
Here is the line: var url = "page.php"; I'm looking to just substitute page.php for whatever.php.
I thought this would be pretty simple and I figured this would work with no issues:
sed -i "s/\url = \".*\"/\url = \"page2.php\"/" /home/site.js
It works okay except instead of getting: var url = "page2.php"; I get: var R1 = "page2.php";
Why is the url value being changed to R1 when I use sed here?
You don't need \ before url.
sed -i -r 's#url\s*=\s*"[^"]+"#url = "page2.php"#' /home/site.js
Extra escaping of " can be eliminated by enclosing sed expression with ' instead of "
It's better to use different separator than / (here #) when the strings themselves may contain /
Try doing this :
sed -i -r 's#(var\s+url\s*=\s*")[^"]+"#\1whatever.php"#' file.js
/ is not mandatory as delimiter, I've picked up # there.
Here's another example: Took me while to figure that you change the / for delimiter and not the / in the directory path.
Use # instead of / for sed delimiter if you have dir path names.
First I tried this:
[root#ip-172-35-24-37 ec2-user]# egrep -q "^(\s*\S+\s+)/dev/shm(\s+\S+\s+\S+)(\s+\S+\s+\S+)(\s*#.*)?\s*$" /etc/fstab && sed -ri "s/^(\s*\S+\s+)/dev/shm(\s+\S+\s+\S+)(\s+\S+\s+\S+)(\s*#.*)?\s*$/\1/dev/shm\2nodev\3\4/" /etc/fstab
And got this error:
sed: -e expression #1, char 20: unknown option to `s'
So then I used # for the sed delimiter instead of /:
[root#ip-172-35-24-37 ec2-user]# egrep -q "^(\s*\S+\s+)/dev/shm(\s+\S+\s+\S+)(\s+\S+\s+\S+)(\s*#.*)?\s*$" /etc/fstab && sed -ri "s#^(\s*\S+\s+)/dev/shm(\s+\S+\s+\S+)(\s+\S+\s+\S+)(\s*#.*)?\s*$#\1/dev/shm\2nodev\3\4##" /etc/fstab
[root#ip-172-35-24-37 ec2-user]#
And it worked.
You can use something else besides # for a delimiter like ! or ? or %. Just don't use / if you have dir paths.

Resources