I'm writing a script to replace dafault configuration values to user specified ones. But i'm getting unterminated 's' command errors from sed. After 2 Hours of googling i still haven't figured out whats causing this. The lines are:
CONFIG_GMETAD_COMPUTENODES="scccompute1 scccompute2"
CONFIG_GMETAD="/etc/gmetad.conf"
sed -i 's/localhost/'${CONFIG_GMETAD_COMPUTENODES}'/g' ${CONFIG_GMETAD}
this substitutes to
sed -i 's/localhost/scccompute1 scccompute2/g' /etc/gmetad.conf
error i get
sed: -e expression #1, char 23: unterminated `s' command
I don't see whats wrong in here, but haven't worked quite often with sed.
You need to quote your variables. Note how the sed command expands:
sed -i 's/localhost/'scccompute1 scccompute2'/g' /etc/gmetad.conf
This creates multiple options, not a single one with your sed script. Instead, try:
sed -i 's/localhost/'"${CONFIG_GMETAD_COMPUTENODES}"'/g' "${CONFIG_GMETAD}"
Containing the variable within double quotes causes the whole string to be treated as a single argument to sed, which is what you want. And of course, quotes around the filename because the filename might contain special characters. As a rule, always quote variables when you refer to them in bash.
Note that if the embedded variable contains slashes or some other special characters, it may break your script. So you might want to do some sanity checking before feeding it to sed:
CONFIG_GMETAD_COMPUTENODES="${CONFIG_GMETAD_COMPUTENODES//[^a-z0-9 ]/}"
This will strip all characters that are not alphanumeric or space, if bash is your shell.
The problem come from quoting in bash.
You should use
sed -i "s/localhost/${CONFIG_GMETAD_COMPUTENODES}/g"
Related
I have 2 bash script variables defined:
THELINENUMBER="14" # an arbitrary line number, comes from a separate command
NEWLINE="a line/ with# special! characters<" # arbitrary line with special characters, comes from separate command
I need to use the line number ${THELINENUMBER} to replace a line in a file called after.txt with ${NEWLINE}.
How do I do that?
These are some examples I have tried:
sed -i '${THELINENUMBER}s#.*#"/"${NEWLINE}"/"' after.txt
sed -i "${THELINENUMBER}s#.*#"/"${NEWLINE}"/"" after.txt
sed -i "${THELINENUMBER}s/.*/'${NEWLINE}'" after.txt
sed -i '${THELINENUMBER}s,.*,${NEWLINE}' after.txt
I am told that the delimitter is usually a /, but those are present in my line replacement variable, so I can't use those. I tried with # and , but the desired behavior did not change. I am also told that " and ' are supposed to be used to turn off escaping in text (use literal string), but I have not been able to get that to work either. How do I pass in a string parameter into sed that has special characters? I am wondering if I should pass the variable ${NEWLINE} into another built-in function call to add escape characters or something before passing it into sed. Is sed the right tool for the job? I did not find much helpful information looking at the CLI manpages. I use Ubuntu 18.04.
I have referred to these sources in my internet search:
https://stackoverflow.com/questions/11145270/how-to-replace-an-entire-line-in-a-text-file-by-line-number
https://askubuntu.com/questions/76808/how-do-i-use-variables-in-a-sed-command
https://stackoverflow.com/questions/37372047/find-a-line-with-a-string-and-replace-entire-line-with-another-line
Use the c (change) command.
By the way, the naming convention for regular shell variables is NOT ALLCAPS, as that may result in accidental collisions with special variables like PATH.
sed "$linenumber c\\
$newline" file
Try
sed -i "${THELINENUMBER}s#.*#${NEWLINE}#" after.txt
this works because:
You require " enclosing the entire sed command instead of backtick so that the variables are expanded
No other quotes or backticks are needed to escape " in the variables as there aren't any: there are no literal (escaped) quotes inside the variables
An alternate separator (such as #) is required due to the / inside the NEWLINE variable.
I want to replace <lexicon uri="file://C:/image/png/grammars/custom/image-custom.lex?SWI.type=backup"/><lexicon uri="file://C:/image/jpg/grammars/custom/image-dot-custom.lex?SWI.type=backup"/> with null in multiple files.
The code is given below.
sed -i s|<lexicon uri="file://C:/image/png/grammars/custom/image-custom.lex?SWI.type=backup"/><lexicon uri="file://C:/image/jpg/grammars/custom/image-dot-custom.lex?SWI.type=backup"/>||g *
Here I am getting this error:
< was unexpected at this time.
Please clarify for me what is not working here.
Could you please try following and let me know if this helps you. By using # as sed's separator you need not to escape / in it only need to escape ., ? not to take their special meaning
sed -E 's#<lexicon uri="file://C:/image/png/grammars/custom/image-custom\.lex\?SWI\.type=backup"/><lexicon uri="file://C:/image/jpg/grammars/custom/image-dot-custom\.lex\?SWI\.type=backup"/>##' Input_file
Tested it with:
sed --version
GNU sed version 4.2.1
works with #
sed -i -e 's#<lexicon uri="file://C:/image/png/grammars/custom/image-custom.lex?SWI.type=backup"/><lexicon uri="file://C:/image/jpg/grammars/custom/image-dot-custom.lex?SWI.type=backup"/>##g' test.txt
The pattern contains shell metacharacters, which need to be quoted or escaped. Usually, in Bash, you should use single quotes around strings, unless you need the shell to interpolate variables and command substitutions and interpret backslash sequences (in which case use double quotes) or to also perform whitespace tokenization and wildcard expansion (in which case use no quotes). See also When to wrap quotes around a shell variable?
sed -i 's|<lexicon uri="file://C:/image/png/grammars/custom/image-custom.lex?SWI.type=backup"/><lexicon uri="file://C:/image/jpg/grammars/custom/image-dot-custom.lex?SWI.type=backup"/>||' *
I also took out the g flag, which only makes sense if you expect multiple matches within a single line. (Perhaps you do after all, in which case obviously put it back.)
Basically a have a "template" file I want to fill with the content of some other auxiliary files which are, basically, a matrix of numbers and letters. I make other substitutions, but this one is what's giving trouble.
In the template file I've put the "%label" at the place I want to do the substitution with the auxiliary file. Then I use this script to do the substitution:
for i in $(cat file_list.txt); do
array[$i]=$(<file_$i.txt)
done
for i in $(cat file_list.txt); do
sed -e "s/%label/${array[$i]}/g"< template.txt > final_file_$i.txt
done
("file_list" contains the files' names) But I keep receiving the error "sed: -e expression #3, char 58: unterminated `s' command".
I've also tried this kind of script to do that:
for i in $(cat file_list.txt); do
mapfile < file_$i.txt
array[$i]=${MAPFILE[#]}
done
for i in $(cat file_list.txt); do
sed -e "s/%label/${array[$i]}/g"< template.txt > final_file_$i.txt
done
In this case I don't receive errors warnings and the substitution is made, but without line breaks.
Is there a way of making the substitution keeping the line breaks?
Thank you.
The problem is that sed requires occurrences of the separator character and occurrences of the newline character in the replacement string for s/// to be escaped with backslashes. The errors reported in the question are due to newlines in the files containing the replacement strings.
It's normally not a good idea to use variables in either the pattern or the replacement string for the s/// command.
Since you are using Bash, you don't need to use sed, or any other external command, for this. Try this pure Bash code:
template=$(< template.txt)
for id in $(< file_list.txt) ; do
contents=$(< "file_$id.txt")
final_contents=${template//%label/"$contents"}
printf '%s\n' "$final_contents" > "final_file_$id.txt"
done
I'm trying to:
sed -i s/installpath/"$INSTALL_PATH"/ /tmp/myscript.conf
when $INSTALL_PATH is just a string everything works. but if install path is an actual path (II guess the '/' char is the problem) like /home/ubuntu/install_script. then It breaks with the following error message:
sed: -e expression #1, char 16: unknown option to `s'
btw: I tried without the "" around $INSTALL_PATH. didn't work
Thanks for the help!
It is likely that $INSTALL_PATH contains slashes, which means that they will be interpreted by sed as part of the s/pattern/replacement/ construct. To avoid this, you should use a different separator, for example ~:
sed -i "s~installpath~$INSTALL_PATH~" /tmp/myscript.conf
I have also wrapped the whole sed line in quotes rather than quoting one section. In general, it's a good idea to do this as it prevents other characters from being interpreted by the shell. Normally single quotes are used but if shell variables are to be expanded, use double quotes.
You don't have to use / as the delimiter in sed commands. Use something that's less likely to occur in a filename, e.g.:
sed -i s^installpath^"$INSTALL_PATH"^ /tmp/myscript.conf
If you're careful with quoting you can use other characters which are even less likely to exist inside a filename:
sed -i "s|installpath|$INSTALL_PATH|" /tmp/myscript.conf
The pipe is outright illegal in Windows paths, and on Linux it's a really bad idea and unlikely to occur in the wild.
I believe this may be a simple question, but I've looked everywhere and tried some workarounds, but I still haven't solved the problem.
Problem description:
I have to replace a character inside a file and I can do it easily using the command line:
sed -e 's/pattern1/pattern2/g' full_path_to_file/file
But when I use the same line inside a bash script I can't seem to be able to replace it, and I don't get an error message, just the file contents without the substitution.
#!/bin/sh
VAR1="patter1"
VAR2="patter2"
VAR3="full_path_to_file"
sed -e 's/${VAR1}/${VAR2}/g' ${VAR3}
Any help would be appreciated.
Thank you very much for your time.
Try
sed -e "s/${VAR1}/${VAR2}/g" ${VAR3}
Bash reference says:
The characters ‘$’ and ‘`’ retain their special meaning within double quotes
Thus it will be able to resolve your variables
I use a script like yours... and mine works as well!
#!/bin/sh
var1='pattern1'
var2='pattern2'
sed -i "s&$var1&$var2&g" *.html
See that, mine use "-i"... and the seperator character "&" I use is different as yours.
The separator character "&" can be used any other character that DOES NOT HAVE AT PATTERN.
You can use:
sed -i "s#$var1#$var2#g" *.html
sed -i "s#$var1#$var2#g" *.html
...
If my pattern is: "test#email.com" of course you must use a seperator different like "#", "%"... ok?