Use sed to comment out .env entry - shell

I'm writing a script that will comment and un-comment field in .env file.
sed -i "s/#SENDGRID_API_KEY/SENDGRID_API_KEY/g" $mlEnv
for uncomment
sed -i "s/[^#]SENDGRID_API_KEY/#SENDGRID_API_KEY/g" $mlEnv
for comment out, I use [^#] so that it will not add one more # when it is already commented
But second one doesnt work, although
grep "[^#]SENDGRID_API_KEY" $mlEnv
works ok.

You may use
sed -i -E 's/(^|[^#])(SENDGRID_API_KEY)/\1#\2/g' "$mlEnv"
Here, -E enables POSIX ERE regex syntax, (^|[^#]) captures (into Group 1) either start of string or any char but # in Group 1 and (SENDGRID_API_KEY) captures SENDGRID_API_KEY in Group 2.
The \1#\2 replacement pattern replaces with Group 1 contents + # + Group 2 contents.
Variables which specify a file name argument should generally be within double quotes.

This might work for you (GNU sed):
sed -Ei 's/^#?(SENDGRID_API_KEY)/#\1/' file
This will replace a line beginning #SENDGRID_API_KEY or SENDGRID_API_KEY with #SENDGRID_API_KEY.

Another try with sed similar to potong's:
sed 's/^[[:space:]]*#*[[:space:]]*\(SENDGRID_API_KEY\)/#\1/' file > newfile
The ^[[:space:]]*#*[[:space:]]*\(SENDGRID_API_KEY\) pattern matches any whitespace, 0+ hash chars, then again any whitespaces and then a SENDGRID_API_KEY word captured in Group 1. The replacement is # and then the captured value.

Related

SED change second occurence in all lines

The normal expression to change server1 to server1-bck is
sed -i 's/server1/server1-bck/g' file.out
so all server1 will be changed to server1-bck. What I need is to change the second occurence of the expression in every line.
For example,
before text:
rename files tsm_node1 //server1/document/users/ //server1/document/users/
desired after text:
rename files tsm_node1 //server1/document/users/ //server1-bck/document/users/
How can I do that?
echo "rename files tsm_node1 //server1/document/users/ //server1/document/users/" |\
sed 's/server1/server1-bck/2g'
sed's famous substitution works like this:
sed 's/regex/replacement/flags'
Flags could be a number, in your case 2 for advising sed to execute this command on 2nd occurrence and if you need more, therefore the g flag is. If you are sure, there are no more items to be substituted, you can leave and forget the g flag.
If you don't pipe and have a file, do this:
sed -i 's/server1/server1-bck/2g' file.out.
Additionally you can replace parts of your regex pattern with sed's & replacement if you want to substitute with that what you have found and will have:
sed -i 's/server1/&-bck/2g' file.out.

remove absolute path using sed command

I have file which contain following context like
abc...
include /home/user/file.txt'
some text
I need to remove include and also complete path after include.
I have used following command which remove include but did not remove path.
sed -i -r 's#include##g' 'filename'
I am also trying to understand above command but did not understand following thing ( copy paste from somewhere)
i - modify file change
r - read file
s- Need input
g - Need input
Try this,
$ sed '/^include /s/.*//g' file.txt
abc...
some text
It remove all the texts in a line which starts with include. s means substitute. so s/.*//g means replace all the texts with null.g means global. The substitution will be applied globally.
OR
$ sed '/^include /d' file.txt
abc...
some text
d means delete.
It deletes the line which starts with include. To save the changes made(inline edit), your commands should be
sed -i '/^include /s/.*//g' file.txt
sed -i '/^include /d' file.txt
I your case if you just want to delete the second line, you can use:
sed -i '2d' file
If you want to explore something about linux commands then man pages are there for you.
Just go to terminal and type:
man sed
as per your question, The above command without -i will show the file content on terminal by deleting the second line from the input file. However, the input file remains unchanged. To update the original file or to make the changes permanently in the source file, use the -i option.
-i[SUFFIX], --in-place[=SUFFIX] :
edit files in place (makes backup if extension supplied)
-r or --regexp-extended :
option is to use extended regular expressions in the script.
s/regexp/replacement/ :
Attempt to match regexp against the pattern space. If success‐
ful, replace that portion matched with replacement. The
replacement may contain the special character & to refer to that
portion of the pattern space which matched, and the special
escapes \1 through \9 to refer to the corresponding matching
sub-expressions in the regexp.
g G : Copy/append hold space to pattern space.
grep -v
This is not about learning sed, but as an alternative (and short) solution, there is:
grep -v '^include' filename_in
Or with output redirection:
grep -v '^include' filename_in > filename_out
-v option for grep inverts matching (hence printing non-matching lines).
For simple deletion that's what I'd use; if you have to modify your path after the include, stick with sed instead.
You can use awk to just delete the line:
awk '/^include/ {next}1' file
sed -i -r 's#include##g' 'filename'
-i: you directly modify the treated file, by default, sed read a file, modify the content via stdout (the original file stay the same).
-r: use of extended regular expression (and not reduce to POSIX limited one).This is not necessary in this case due to simple POSIX compliant action in action list (the s### string).
s#pattern#NewValue#: substitute in current line the pattern (Regular Expression) with "Newvalue" (that also use internal buffer or specific value). The traditionnal form is s/// but in this case, using / in path (pattern or new value) an alternate form is used to avoid to escape all / in pattern or new value
g: is an option of s### that specify change EVERY occurence and not the first (by default)
so here it replace ANY occurence of include by nothing (remove) directly into your file
As per the Avinash Raj solution you got what you want but you want some explaination about some parameter used in sed command
First one is
command: s for substitution
With the sed command the substitute command s changes all occurrences of the regular expression into a new value. A simple example is changing "my" in the "file1" to "yours" in the "file2" file:
sed s/my/yours/ file1 >file2
The character after the s is the delimiter. It is conventionally a slash, because this is what ed, more, and vi use. It can be anything you want, however. If you want to change a pathname that contains a slash - say /usr/local/bin to /common/bin - you could use the backslash to quote the slash:
sed 's/\/usr\/local\/bin/\/common\/bin/' <old >new
/g - Global replacement
Replace all matches, not just the first match.
If you tell it to change a word, it will only change the first occurrence of the word on a line. You may want to make the change on every word on the line instead of the first then add a g after the last delimiter and use the work-around:
Delete with d
Delete the pattern space; immediately start next cycle.
You can delete line by specifying the line number. like
sed '$d' filename.txt
It will remove last line of file
sed '2 d' file.txt
It will delete second line of file.
-i option
This option specifies that files are to be edited in-place. GNU sed does this by creating a temporary file and sending output to this file rather than to the standard output.
To modify file actully you can use -i option without it sed command repressent changes on stdout not actual file. You can take backup of original file before modification by using -i.bak option.
-r option
--regexp-extended
Use extended regular expressions rather than basic regular expressions. Extended regexps are those that egrep accepts; they can be clearer because they usually have less backslashes, but are a GNU extension and hence scripts that use them are not portable.

sed replace end of specific string in file

I have a hash file that takes the form of:
SHA1(disk.iso)= 43798473890473280573920473902472083947320
I need to replace the old hash with the new hash.
I've been trying to modify some old code with no luck:
sed -i 's/SHA1(disk.iso)"[^+]*"/"'" $HASH"'"/' manifest
Any thoughts here?
* UPDATE *
The sting listed above is correct:
SHA1(disk.iso)= (some SHA1 hash here. Note the space after the equal sign.)
Here is the current code:
sed -i "s/\(SHA1(disk.iso)=\).*/\1 $HASH/" manifest
but still nothing. This does not modify the line in question.
* SOLUTION *
THIS WORKS:
sed -i "s/\(SHA1(disk.iso)=\).*/\1 $HASH/" manifest
I just had the file name wrong. Thank you Janos
Here you go:
sed -i "s/\(SHA1(disk.iso)=\).*/\1 $HASH/" manifest
That is:
Capture the filename within \(...\), and match the rest of the line with .*
Replace the pattern (the entire line) with the captured filename \1, and append the $HASH
The whole thing within double quotes, so that shell variables are expanded.
Here's another variation to do the same thing:
sed -i "/^SHA1(disk.iso)/ s/=.*/= $HASH/" manifest
That is:
For lines starting with SHA1(disk.iso)
Replace the = sign and everything after it with = $HASH
You regular expression seems to be strange.
You use to many quotes.
You can just do (if you now the hashes):
sed -i "s/$OLDHASH/$NEWHASH" manifest
And if you don't know them and just want to replace any line with SHA1(disk.iso),
you can write:
sed -i "s/\(SHA1(disk.iso)=\).*/\1 $HASH/"
\(\) here mean backreferences; that means that you save the line in a register, that will be later used using \1. Of course, you could write directly:
sed -i "s/SHA1(disk.iso)=.*/SHA1(disk.iso) $HASH/"
but in this case it would be impossible to write something like disk[123].iso
to match several ISOs at once.
Two steps:
find the right line
replace the number in that line with a new number
Typically you do this with
cat myHashFile.txt | sed '/SHA1(disk.iso)/ {s/\d+/'$HASH'/}' > newHashFile.txt
The first term in /.../ in general takes a regular expression "apply what follows to lines meeting this condition"
The second part in {..} is the command:
s substitute
\d any digit
\d+ one or more digits (greedy)
$HASH replace with the contents of the $HASH variable

BASH: insert text in a specific position

I would like to find a solution to add some characters in a string
Example
folder/dir/directory/file.txt
shares/page.html
etc/downloads/torrent.torrent
Should become
.folder.old/dir/directory/file.txt
.shares.old/page.html
.etc.old/downloads/torrent.torrent
How can i do that? 'grep' would be a correct choose?
Thank you
Use sed instead of grep:
sed -i.bak 's#^\([^/]*\)#.\1.old#'
Note that -i will save the result in the original file itself. -i.bak will save your original file with .bak extension in case something goes wrong.
grep only searches, it doesn't do replacement. You want sed:
sed -i.bak 's#^\([^/]*\)#.\1.old#'
^ means beginning of the line
\(...\) is capturing parentheses, the pattern it matches becomes \1 in the replacement.
[^/] matches anything but /
* is zero or more of the preceding

How to apply two different sed commands on a line?

Q1:
I would like to edit a file containing a set of email ids such that all the domain names become generic.
Example,
peter#yahoo.com
peter#hotmail.co.in
philip#gmail.com
to
peter_yahoo#generic.com
peter_hotmail#generic.com
philip_gmail#generic.com
I used the following sed cmd to replace # with _
sed 's/#/_/' <filename>
Is there a way to append another sed cmd to the cmd mentioned above such that I can replace the last part of the domain names with #generic.com?
Q2:
so how do I approach this if I had text at the end of my domain names?
Example,
peter#yahoo.com,i am peter
peter#hotmail.co.in,i am also peter
To,
peter_yahoo.com#generic.com,i am peter
peter_hotmail.co.in#generic.com,i am also peter
I tried #(,) instead of #(.*)
it doesn't work and I cant think of any other solution
Q3:
Suppose if my example is like this,
peter#yahoo.com
peter#hotmail.co.in,i am peter
I want my result to be as follows,
peter_yahoo.com#generic.com
peter_hotmail.co.in#generic.com,i am peter,i am peter
How do i do this with a single sed cmd?
The following cmd would result in,
sed -r 's!#(.*)!_\1#generic.com!' FILE
peter_yahoo.com#generic.com
peter_hotmail.co.in,i am peter,i am peter#generic.com
And the following cmd wont work on "peter#yahoo.com",
sed -r 's!#(.*)(,.*)!_\1#generic.com!' FILE
Thanks!!
Golfing =)
$ cat FILE
Example,
peter#yahoo.com
peter#hotmail.co.in
philip#gmail.com
$ sed -r 's!#(.*)!_\1#generic.com!' FILE
Example,
peter_yahoo.com#generic.com
peter_hotmail.co.in#generic.com
philip_gmail.com#generic.com
In reply to user1428900, this is some explanations :
sed -r # sed in extended regex mode
s # substitution
! # my delimiter, pick up anything you want instead !part of regex
#(.*) # a literal "#" + capture of the rest of the line
! # middle delimiter
_\1#generic.com # an "_" + the captured group N°1 + "#generic.com"
! # end delimiter
FILE # file-name
Extended mode isn't really needed there, consider the same following snippet in BRE (basic regex) mode :
sed 's!#\(.*\)!_\1#generic.com!' FILE
Edit to fit your new needs :
$ cat FILE
Example,
peter#yahoo.com,I am peter
peter#hotmail.co.in
philip#gmail.com
$ sed -r 's!#(.*),.*!_\1#generic.com!' FILE
Example,
peter_yahoo.com#generic.com
peter#hotmail.co.in
philip#gmail.com
If you want only email lines, you can do something like that :
sed -r '/#/s!#(.*),.*!_\1#generic.com!' FILE
the /#/ part means to only works on the lines containing the character #
Edit2:
if you want to keep the end lines like your new comments said :
sed -r 's!#(.*)(,.*)!_\1#generic.com\2!' FILE
You can run multiple commands with:
sed -e cmd -e cmd
or
sed -e cmd;cmd
So, in your case you could do:
sed -e 's/#/_/' -e 's/_.*/_generic.com/' filename
but it seems easier to just do
sed 's/#.*/_generic.com/' filename
sed 's/\(.*\)#\(.*\)\..*/\1_\2#generic.com/'
Expression with escaped parentheses \(.*\) is used to remember portions of the regular expression. The "\1" is the first remembered pattern, and the "\2" is the second remembered pattern.
The expression \(.*\) before the # is used to remember beginning of the email id (peter, peter, philip).
The expression \(.*\)\. after the # is used to remember ending of the email id (yahoo, hotmail, gmail). In other words, it says: take something between # and .
The expression .* at the end is used to match all trailing symbols in the e-mail id (.com, .co.in, .co.in).

Resources