i am having trouble replacing the modified date in my script via sed.
I am getting the last modified date like this:
olddate=`grep -m1 "Built " script.sh | cut -c 22-29`
I get the current date with:
newdate=`date +%d/%m/%y`
Basically i want to replace old date with new date
sed -i "" "s/$olddate/$newdate/g" script.sh
But this doesn't work as the date contains slashes. I've looked around and i can't find the way to escape them properly. Any help would be appreciated.
You can use separators other than slashes, for instance ";"
sed -i "" "s;$olddate;$newdate;g" script.sh
Use , instead of / !
sed -i "" "s,$olddate,$newdate,g" script.sh
In fact you can use almost any char as separators.
use sed "s#$olddate#$newdate#g"
that should work
Related
I'm on macOS and have a file with a bunch of logs and their timestamps. The timestamps have the format "seconds since Epoch", but I want to replace them all with the format "MM-DD-YY HH:MM:SS". So for example:
1605726368.416115 seconds since the Epoch should be replaced with 11-18-20 20:06:08. Note the seconds since Epoch timestamps are decimal values, that's just how the logs are timestamped.
I'm trying to realize this with sed and date as follows:
sed -E -i '' -e "s/^([0-9]+)([0-9.]+)/$(date -r \1 '+%m-%d-%Y %X')/" logfile.txt
The problem is that date interprets \1 as just 1 second instead of the back reference that refers to the ([0-9]+) capture group in the regex. I've tried a bunch of things like replacing \1 with $1 or \\1, messing around with single- and double-quotes, and installing gnu-sed from homebrew and trying it with the /e flag, and nothing works. So my question is basically: Is it possible to use a \N back reference within a $(...) command substitution (specifically in the context of a sed replace string)?
If possible, I want to avoid reading each line in a while loop and calling sed on each line because that is super slow.
You cannot do a command substitution over a back-reference of a captured value in sed as command substitution will run before and it will take literal \1 instead of the actual captured value.
If you are fine with a perl solution then this will work fine:
perl -pe 's/^[0-9]+\.[0-9]+/{
use POSIX qw( strftime ); strftime("%m-%d-%Y %X", localtime($&));
}/e' file.log
PS: You may use gmtime instead of localtime if your EPOCH value is in GMT.
I will start with two bad solutions with paste, that might amuse you.
When all lines start with a timestamp, you can use
paste -d " " <(printf '%(%m-%d-%Y %X)T\n' $(cut -d"." -f1 logfile.txt)) \
<(cut -d" " -f2- logfile.txt)
This will fail for a line with only a linestamp, for the next years you can use
paste -d " " <(printf '%(%m-%d-%Y %X)T\n' $(cut -d"." -f1 logfile.txt)) <(cut -c19- logfile.txt)
You can use sed almost like you did. First extract the commands and next source them.
. <(sed -E 's/^([0-9]+)([0-9.]+)(.*)/printf "%(%m-%d-%Y %X)T" "\1"; echo "\3"/' logfile.txt)
I think awk is best:
awk -F "." '{ print strftime("%m-%d-%Y %X",$1) substr($0,17) }' logfile.txt
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.
i want to replace this
#!/usr/bin/env bash
with this
#!/bin/bash
i have tried two approaches
Approach 1
original_str="#!/usr/bin/env bash"
replace_str="#!/bin/bash"
sed s~${original_str}~${replace_str}~ filename
Approach 2
line=`grep -n "/usr/bin" filename`
awk NR==${line} {sub("#!/usr/bin/env bash"," #!/bin/bash")}
But both of them are not working.
You cannot use ! inside a double quotes in BASH otherwise history expansion will take place.
You can just do:
original_str='/usr/bin/env bash'
replace_str='/bin/bash'
sed "s~$original_str~$replace_str~" file
#!/bin/bash
Using escape characters :
$ cat z.sh
#!/usr/bin/env bash
$ sed -i "s/\/usr\/bin\/env bash/\/bin\/bash/g" z.sh
$ cat z.sh
#!/bin/bash
Try this out in the terminal:
echo "#!/usr/bin/env bash" | sed 's:#!/usr/bin/env bash:#!/bin/bash:g'
In this cases I use : because sed gets confused between the different slashes and it isn't able to tell anymore with one separates and wich one is part of the text.
Plus it looks really clean.
The cool thing is that you can use every symbol you want as a separator.
For example a semicolon ; or the pipe symbol | .
By using the escape character \ I think that the code would look too messy and wouldn't be very readable, considering the fact that you have to put it before every forward slash in the command.
The command above will just print out the replaced line, but if you want to modify the file, than you need to specify the input and output file, like this:
sed 's:#!/usr/bin/env bash:#!/bin/bash:g' <inputfile >outputfile-new
Remember to put that -new if the inputfile and the output file have the same name, because without it your original one will be cleared completely: this happend me in the past, and it's not the best thing at all. For example:
<test.txt >test-new.txt
I am getting the error "unterminated substitute pattern" on mac os when attempting to replace multiple words with a different set of multiple words separated by spaces. I am doing this in a bash script. Reading from csv to replace a set of strings in files.
example
while IFS=, read col1 col2 col3
#$col1=FOO BAR
#$col2=another set of words
#$col3=file
do
REGX="'s|$col2|$col3|g'"
sed -i -e $REGX $col1
done < $config_file
I want the output to be "another set of words" can't seem to find out how to allow the spaces in the expression.
Thanks
You are defining the substitution to do in a variable so that you use later on:
REGX="'s|$col2|$col3|g'"
sed -i -e REGX col3
Another example:
$ cat a
hello this is a test
$ REGX="s/this/that/g"
$ sed $REGX a
hello that is a test
However, I would directly use the command as follows:
while IFS=, read -r col1 col2 col3
do
sed -i.bak -e "s|$col2|$col3|g" $col1
done < $config_file
Notes:
Use -r in read to avoid weird situations on corner cases.
Use double quotes in sed so that the variables within the expression are evaluated. Otherwise, it will look for literal $col2 and change with literal $col3.
Use -i.bak to create backup files when using -i. Otherwise, if you try and fail... you will lose your original document.
sed -i "s#foo bar#another set of words#g"
# OR
sed -i "s#foo|bar#another string#g"
sed use | as regex OR, use another separator (the default / suite well here also)
Having the following in a file:
public $password = 'XYZ';
I'm trying to replace the password's value with a different one, through an automated deployment process from backup files.
I have the regext that will match the string above in a file, but not much compatible with sed
(public\s\$password\s=\s'(.*)'?)
I also tried
sed -i -e "s/public\s\$password\s=\s'(.*)'/private\s\$password\s=\s'jingle'" configuration.php
Any ideas?
Try this:
sed -i -e "s/public\s\$password\s=\s'\(.*\)'/private \$password = 'jingle'/" configuration.php
The problem was that you need to 'escape' the round brackets, and that \s doesn't work in the output pattern. You also had missed the final /.