Variables not working in sed command - shell

How to use a variable instead of 3 in the command below?
sed -i '3s/$/ newvalue/' filename
I tried
var=1
sed -i '$vars/$/ newvalue/' filename
sed -i "$vars/$/ newvalue/" filename

First, you need to use double quotes to allow shell parameters/variables to expand. Then, you need to use braces to isolate the variable name if text that follows the variable could be interpreted as part of variable name (before${var}after). Finally, to use literal $ under double quotes, you should escape it a blackslash. All together:
var=3
sed -i "${var}s/\$/ newvalue/" filename
One alternative is to use alternating double and single quotes (under which no character is treated specially, including $ for parameter expansion):
sed -i "$var"'s/$/ newvalue/' filename

Related

Remove everything after nth occurrence of character, using sed [duplicate]

I am trying to change the values in a text file using sed in a Bash script with the line,
sed 's/draw($prev_number;n_)/draw($number;n_)/g' file.txt > tmp
This will be in a for loop. Why is it not working?
Variables inside ' don't get substituted in Bash. To get string substitution (or interpolation, if you're familiar with Perl) you would need to change it to use double quotes " instead of the single quotes:
# Enclose the entire expression in double quotes
$ sed "s/draw($prev_number;n_)/draw($number;n_)/g" file.txt > tmp
# Or, concatenate strings with only variables inside double quotes
# This would restrict expansion to the relevant portion
# and prevent accidental expansion for !, backticks, etc.
$ sed 's/draw('"$prev_number"';n_)/draw('"$number"';n_)/g' file.txt > tmp
# A variable cannot contain arbitrary characters
# See link in the further reading section for details
$ a='foo
bar'
$ echo 'baz' | sed 's/baz/'"$a"'/g'
sed: -e expression #1, char 9: unterminated `s' command
Further Reading:
Difference between single and double quotes in Bash
Is it possible to escape regex metacharacters reliably with sed
Using different delimiters for sed substitute command
Unless you need it in a different file you can use the -i flag to change the file in place
Variables within single quotes are not expanded, but within double quotes they are. Use double quotes in this case.
sed "s/draw($prev_number;n_)/draw($number;n_)/g" file.txt > tmp
You could also make it work with eval, but don’t do that!!
This may help:
sed "s/draw($prev_number;n_)/draw($number;n_)/g"
You can use variables like below. Like here, I wanted to replace hostname i.e., a system variable in the file. I am looking for string look.me and replacing that whole line with look.me=<system_name>
sed -i "s/.*look.me.*/look.me=`hostname`/"
You can also store your system value in another variable and can use that variable for substitution.
host_var=`hostname`
sed -i "s/.*look.me.*/look.me=$host_var/"
Input file:
look.me=demonic
Output of file (assuming my system name is prod-cfm-frontend-1-usa-central-1):
look.me=prod-cfm-frontend-1-usa-central-1
I needed to input github tags from my release within github actions. So that on release it will automatically package up and push code to artifactory.
Here is how I did it. :)
- name: Invoke build
run: |
# Gets the Tag number from the release
TAGNUMBER=$(echo $GITHUB_REF | cut -d / -f 3)
# Setups a string to be used by sed
FINDANDREPLACE='s/${GITHUBACTIONSTAG}/'$(echo $TAGNUMBER)/
# Updates the setup.cfg file within version number
sed -i $FINDANDREPLACE setup.cfg
# Installs prerequisites and pushes
pip install -r requirements-dev.txt
invoke build
Retrospectively I wish I did this in python with tests. However it was fun todo some bash.
Another variant, using printf:
SED_EXPR="$(printf -- 's/draw(%s;n_)/draw(%s;n_)/g' $prev_number $number)"
sed "${SED_EXPR}" file.txt
or in one line:
sed "$(printf -- 's/draw(%s;n_)/draw(%s;n_)/g' $prev_number $number)" file.txt
Using printf to build the replacement expression should be safe against all kinds of weird things, which is why I like this variant.

How do I escape a single quote inside single quotes in jenkins-pipeline bash command

in jenkins-pipeline, I'm trying to use SED to append the following line to the end of a file.
sh "sed -i '\$ s/\$/ public_file=\\/var\\/lib\\/jenkins\\/workspace\\/test-project\\ ansible_ssh_common_args='-o StrictHostKeyChecking=no' /' file.txt"
but I can't figure out how to escape the below line in my Jenkins file to make it work.
ansible_ssh_common_args='-o StrictHostKeyChecking=no'
I've already tried the following, which works in katacoda playground, but not in jenkins pipeline.
'"'"'-o StrictHostKeyChecking=no'"'"' /' file.txt
use " to wrap sed command, then you can use ' in command directly without to escape it.
use #, but / as delimiter for sed s command, then you no need to escape the / appeared in file path to make the whole commend more concise and readable.
sed -i "\$ s#\$# public_file=/var/lib/jenkins/workspace/test-project ansible_ssh_common_args='-o StrictHostKeyChecking=no' #" file.txt
In bash, you cannot escape single quotes within single quotes.
See the bash manual page:
Enclosing characters in single quotes preserves the literal value of each character within the quotes. A single quote may not occur between single quotes, even when preceded by a backslash.
You can use double quotes instead; then escape them as needed. You can then use single quotes within them without further escaping.

Insert single quote with sed

I want to add some text on a line:
sudo sed -i '5imytext 16/16' /file
Now I've added mytext 16/16 on line 5 of the file, but I actually want to add the text 'mytext' 16/16 (mytext between single quotes).
I tried
sudo sed -i '5i'mytext' 16/16' /file
but it didn't work. Can someone help me?
The single quotes that you're trying to use in your insertion string are interfering with the ones around the sed command.
The simplest thing to do is to use different quotes around your sed command:
"5i'mytext' 16/16"
Normally it's best to use single quotes around a sed command but it would be more tricky in this case:
'5i'"'"'mytext'"'"' 16/16'
Basically, you need to put the single quotes inside double quotes somehow and in this case there's no reason not to double quote the whole command.
As suggested by 123 in the comments, an alternative would be to put your sed command into a script file:
5i'mytext' 16/16
Then use the -f switch to sed:
sed -f script
This avoids the need to use two kinds of quotes.
Use double quote in these cases. Because:
Single quote can't have single quote inside it. ('\'' won't work)
Double quote can have both single quote and double quote inside it. ("'\"" will work)
Example:
sudo sed -i "5i'mytext' 16/16" /file
You could use double quotes around your sed command, but that won't help you if you also need to insert double quotes. An alternative would be to use: \x27
Example: echo a|sed 's/a/\x27/' ➡ '

Path substitution with sed and shell variables on OS X

I am on Mac OS X and using sed for an in-place replacement.
Essentially I have this:
#!/bin/sh -e
PREFIX="$1"
sed -i bak -e 's|OCAMLDIR|"${PREFIX}"|g' ocamloptrev
Where PREFIX is a path, hence I'm using the |.
Unfortunately, the variable in the file path is not getting evaluated as I expected, I end up with:
OCAMLC="${PREFIX}"/bin/ocamlopt
How can I get the right evaluation of ${PREFIX} into the sed command?
Try this:
#!/bin/sh -e
PREFIX="$1"
sed -i bak -e 's|OCAMLDIR|'"${PREFIX}"'|g' ocamloptrev
What you're basically doing, is "exiting"/getting outside the single-quoted string, entering into a double-quoted string, interpreting the variable inside double-quotes, and then entering the single quotes again.
With this simple example, we could also just use double-quotes, which allow variables to be interpreted:
#!/bin/sh -e
PREFIX="$1"
sed -i bak -e "s|OCAMLDIR|${PREFIX}|g" ocamloptrev
If you try to use double-quotes ("") inside single-quotes, they don't get interpreted either. This part of the Bash manual explains this in more detail.
3.1.2.2 Single Quotes
Enclosing characters in single quotes (‘'’) preserves the literal value of each character within the quotes. A single quote may not occur between single quotes, even when preceded by a backslash.
3.1.2.3 Double Quotes
Enclosing characters in double quotes (‘"’) preserves the literal value of all characters within the quotes, with the exception of $, `, \, and, when history expansion is enabled, !. The characters $ and ` retain their special meaning within double quotes (see Shell Expansions). ...
Shell variables are not expanded inside single quotes (there are no metacharacters within single quotes, not even backslashes), so you need to use something like this, with the double quotes around ${PREFIX} ensuring that spaces etc in the value are handled correctly:
sed -i bak -e 's|OCAMLDIR|'"${PREFIX}"'|g' ocamloptrev
Or you could even use:
sed -i bak -e "s|OCAMLDIR|${PREFIX}|g" ocamloptrev
The latter is safe because the material inside the double quotes does not contain shell metacharacters (dollar signs, backslashes and back-quotes are the main danger signs). If there were dodgy characters in the rest of the string, the first version is safer to use.
Personally, I'd use .bak rather than just bak as the suffix.

cant figure out proper syntax for sed using double quotes

I have an variable
qsubFile="submitJob.sh"
echo $qsubFile returns submitJob.sh without the double quotes.
Now, I want to find the line containing the string qsubFile="someOtherFile.sh" and replace it to qsubFile="submitJob.sh" in the file "write.sh".
I tried using
sed -i '/qsubFile=/c\qsubFile="'"$qsubFile"'"' write.sh
qsubFile=""
I can't seem to get the proper syntax for this.
but it replaces it as
You just need single quotes for sed to do this, there is no problem with the double quotes inside the single quotes:
sed -i 's/qsubFile="someOtherFile.sh"/qsubFile="submitJob.sh"/g' write.sh
If "someOtherFile.sh" isn't a fixed string in write.sh than use the follow to replace them all:
$ sed -i 's/qsubFile="[^"]*"/qsubFile="submitJob.sh"/g' write.sh
Regex "[^"]*":
" # double quote
[^"]* # Anything not a double quote
" # double quote
Seems I misread the question the first time the correct quoting is to use the variable $qsubFile is, you missed the last /:
sed -i 's/qsubFile="[^"]*"/qsubFile="'"$qsubFile"'"/g' write.sh
You're somewhat on the right track if you need to use the shell variable though.
sed -i 's/qsubFile="someOtherFile.sh"/qsubFile="'"$qsubfile"'"/g' write.sh
or if you want to make sure you get the whole line
sed -i 's/^\(qsubFile=\).*$/\1"'"$qsubfile"'"/g' write.sh

Resources