SED command in linux to edit a file with script [duplicate] - regex

This question already has answers here:
Using Sed to expand environment variables inside files
(2 answers)
Closed 8 years ago.
I have a file name temp.txt with content as
ANSWER "1234:IDGK"
ANSWER "123456:DEF"
I need to change answer "1234:$1"with input parameter from script.
Right now, I am using the code below in script (run.sh) to change the content in temp.txt
#!/bin/bash
Prompt1=$1
sed -i -e "s/\(1234:\).*/\1$1/" temp.txt
But when I run the script with any input value {irrespective of length of value} " is over written in temp.txt.
for example
./run.sh ABCDEF
temp.txt is updated as
ANSWER "1234:ABCDEF
ANSWER "123456:DEF"
The expected output is
ANSWER "1234:ABCDEF"
ANSWER "123456:DEF"
Note: input value in file will always not be same so I can't go with
sed s/IDGK/ABCDEF/g
Please suggest correct SED command which will replace the only text and not the ".

Since you don't want the trailing double quote deleted, you need to exclude it from the substitution. For example:
sed -i -e "s/\(1234:\).*\(.\)/\1$1\2/" temp.txt
The second capture matches the last character on the line, the double quote.
Or:
sed -i -e 's/\(1234:\)[^"]*'"/\1$1/" temp.txt
Instead of matching any character, only match characters that are not double quotes. Note the use of single quotes and double quotes to ensure the double quote in the negated character class is a double quote. Alternatively again:
sed -i -e "s/\(1234:\)[^\"]*/\1$1/" temp.txt
This escapes the double quote with a backslash. It isn't the way I'd do it, but it will work fine.

You can try this.
sed -i -e 's/\(1234:\).*/\1'$1'"/' temp.txt
Last character will be the double quotes. So you can directly place that in the substitution. Or else you can try this.
sed -i -e 's/\(1234:\)[^"]*/\1'$1'/' temp.txt
If your system not allow to use the -i option, you can use the redirect like this.
sed -e 's/\(1234:\)[^"]*/\1'$1'/' temp.txt > temp.txt

Related

Using sed with regex to find and replace a string

So I have the following string in my config.fish, and init.vim:
Fish: eval sh ~/.config/fish/colors/base16-monokai.dark.sh
Vim: colorscheme base16-monokai
Vim: let g:airline_theme='base16_monokai'
And I have the following shell script:
#!/bin/sh
theme=$1
background=$2
if [ -z '$theme' ]; then
echo "Please provide a theme name."
else
if [ -z '$background' ]; then
$background = 'dark'
fi
base16-builder -s $theme -t vim -b $background > ~/.config/nvim/colors/base16-$theme.vim &&
base16-builder -s $theme -t shell -b $background > ~/.config/fish/colors/base16-$theme.$background.sh &&
base16-builder -s $theme -t vim-airline -b $background > ~/.vim/plugged/vim-airline-themes/autoload/airline/themes/base16_$theme.vim
sed -i -e 's/foo/eval sh ~/.config/fish/colors/base16-$theme.$background.sh/g' ~/Developer/dotfiles/config.fish
sed -i -e 's/foo/colorscheme base16-$theme/g' ~/Developer/dotfiles/init.vim
sed -i -e 's/foo/let g:airline_theme='base16_$theme'/g' ~/Developer/dotfiles/init.vim
fi
Basically the idea is the script will generate whichever theme is passed through using this builder.
I have tried referring this documentation but I am not very skilled at regex so if anybody could give me a hand I would appreciate it.
What I need to happen is once the script is generated sed will look for the above strings and replace theme with the newly generated theme ones.
Try this :
sed -i "s|\(eval sh ~/\.config/fish/colors/base16-\)\([^.]*\)\.\([^.]*\)\\(.*\)|\1$theme.$background\4|
" ~/Developer/dotfiles/config.fish
sed -i "s/\(base16\)\([-_]\)\([a-zA-Z]*\)/\1\2$theme/g" ~/Developer/dotfiles/init.vim
Assuming in the second sed command that the theme is an alphanumeric string. If not, you can complete the character range : [a-zA-Z] with additional characters (eg [a-zA-Z0-9]).
You can replace something in sed using this syntax: sed "s#regex#replacement#g". Because you have /s and 's in your strings, it's easiest not to need to escape them.
There are some characters that need to be escaped to make the regexes. . and $ need to be escaped with a \. The $ in the replacement string needs to be escaped too.
If you want to capture a certain part from match, it's easiest to use char classes. For example, eval sh ~/\.config/fish/colors/base16-([^.]+)\.dark\.sh would be the regex to use if you want your replacement to be airline_theme='$1_base16_\$theme'. In that case, the $1 in the replacement is the thing captured in the regex.
[^.]+ will capture everything up to the next .
I hope this helps you to better understand regexes! This should be detailed enough to show you how to write your own.
You need to use double quotes for parameter expansion not single quotes.
You need to escape the single quotes: 'hello'\''world'
I will make one line for you and leave it as an exercise to fix the other lines
sed -i -e 's~\(let g:airline_theme='\''\)[^'\'']*\('\'\)'~base16_'"$theme"~' ~/Developer/dotfiles/init.vim
The first character after the s in the sed expression string is used as the pattern separator, so by putting / first you have specified / as the separator.
Additionally using the single quote tells the shell not to expand any variables, you are going to want to use double quotes instead.
try something like
sed -i -e "s#foo#eval sh ~/.config/fish/colors/base16-$theme.$background.sh#g" ~/Developer/dotfiles/config.fish
as you've now commented that you needed to find the previous theme string instead of foo
sed -i -e "s#eval sh \~/\.config/fish/colors/base16-.*?\..*?\.sh#eval sh ~/.config/fish/colors/base16-$theme.$background.sh#g" ~/Developer/dotfiles/config.fish

sed got error if no single quotes around the regular expression

I tried to do the following command in bash:
ls -1 | sed s/\(.*\)/"\1"/
which is add double quotes around each output of ls, but the result shows
sed: 1: "s/(.*)/\1/": \1 not defined in the RE
after I add single quotes around the regular expression, I got the right result. the right one is:
ls -1 | sed 's/\(.*\)/"\1"/'
theocratically I do not need the outer quotes right? any one has the same experience?
Single quotes are used to disable shell parsing of various sequences including backslash escapes. If you don't use them, your sequences like \( are passed to sed as (. You may check that by adding echo to the beginning of your command.
Sending the command to echo will show you what sed sees
$ echo sed s/\(.*\)/"\1"/
sed
Hmm, the sed script disappeared altogether. The exposed "*" is forcing the shell to try to match files. Let's disable that:
$ set -f
$ echo sed s/\(.*\)/"\1"/
sed s/(.*)/\1/
The shell ate the quotes and the backslashes. Quoting the sed script:
$ echo sed 's/\(.*\)/"\1"/'
sed s/\(.*\)/"\1"/
That gives the right result, sed will see the script you want to give it. How can we do that without quotes
$ echo sed s/\\\(.\*\\\)/\"\\1\"/
sed s/\(.*\)/"\1"/
And that's ugly.

sed command not updating text file [duplicate]

This question already has answers here:
How to use variables in a command in sed?
(4 answers)
Closed 8 years ago.
Would like to ask because I'm having an issue with sed command in unix scripting.
#!/bin/sh
cnt=2
sed '1 c\
$cnt' test.txt
I want to replace the first line of text file test.txt with the value of variable cnt which is 2. How can I pass the variable on the above sed command? The sed command treats $cnt as string.
Variables are not expanded in single quotes. They are expanded in double quotes, though.
sed "1 c\\
$cnt" test.txt
Note that sed doesn't update the input file by default, it outputs the changed version instead. If your implementation of sed supports it, use the -i switch to modify the input file. Otherwise, you'd have to redirect the output to a new file and rename it back to the original name:
sed "..." text.txt > text.new
mv text.new text.txt
Change to:
#!/bin/sh
cnt=2
sed "1 c\
$cnt" test.txt
For variable interpolation to happen, u need to put it within double quotes rather than single quotes.

Sed command does not replace string with special characters [duplicate]

This question already has answers here:
sed search and replace strings containing / [duplicate]
(2 answers)
Closed 8 years ago.
I have a script which is getting value from a ".properties" file. It replaces the value successfully if it is a simple string but if contains escape characters like ('\') it does not work. Can anybody point out please that what to do, i have searched on the internet but unable to understand the "REGEX".
Script File:
#!/bin/bash
# Omer's First Script
#Include Properties File
. directoryPaths.properties
echo "Start"
sed -i "s/DONEDIRECTORY/$DoneDirectory/" *TestFile*
echo "finish"
directoryPaths.properties
DoneDirectory=/home/omerkhalid/Documents/Test/Done
TestFile.txt
This is a test Document.
DONEDIRECTORY
Error:
sed: -e expression #1, char 18: unknown option to `s'
Note:
If i change the value of "DoneDirectory" to simple string i.e. "Done" , it works fine. But with "/" escape characters it doesn't work.
Problem is not with the sed command but with the contents of the variable $DoneDirectory.
In the sed command
sed -i "s/DONEDIRECTORY/$DoneDirectory/" *TestFile*
/ is used as the delimitter, there by sed expects only 3 slashes following the s command. But once the variable $DoneDirectory is substituted there are 8 / which gives the error
Solution
Use some other delimeters in sed like
sed -i "s#DONEDIRECTORY#$DoneDirectory#" *TestFile*
Since the variable $DoneDirectory contains sed's default command delimiter / I would use a different delimiter:
sed -i "s#DONEDIRECTORY#$DoneDirectory#" *TestFile*
I would argue that sed is not the right tool for this job. Sure, you can work with other delimiters, but if the other delimiter shows up in your string (or a backslash, or something else that sed interprets), it's still going to explode. I believe awk is better suited:
awk -v subst="$DoneDirectory" '{ sub("DONEDIRECTORY", subst); print $0 }' TestFile
Note: use gsub instead of sub if DONEDIRECTORY can show up more than once in a line and both should then be substituted.

Replace newline with string in sed on mac

In a file, I need to replace all newlines (not the escape sequence '\n', but the actual newline) with a string. All the questions I've found on SO have been the other way around; i.e. replacing a string with a literal newline. This is on a Mac.
I've tried the following
sed -i '' 's/\
/STOP/g' file.txt
But it gives me an "unterminated substitute pattern" error.
While it can be done using sed also but doing this with awk is much simpler:
awk -v ORS='STOP' '1' file
This changes output record separator to STOP instead of default \n.
Update: Here is a sed version to do same on OSX:
sed -i.bak -n -e 'H;${x;s/\n/STOP/g;p;}' file