How to search and replace in a line using sed - sed

I have a file content like this
select b.id as cli_id,b.login as cli_login, b.pname as cli_name,
b.cname as cli_company, b.phone as cli_phone, b.email as cli_email,
(select (value / 1048576) from Limits where limit_name='disk_space'
and id=b.limits_id) as Client_Package, b.cr_date, (select
FROM_UNIXTIME(value,"%Y-%m-%d") from Limits where
limit_name='expiration' and id=b.limits_id) as Client_expire,
If(b.status=0,'Active','Inactive') as Cli_Status, a.name as dom_name,
If(a.status=0,'Active','Inactive') as Dom_Package, a.cr_date as
dom_create, (select FROM_UNIXTIME(value,"%Y-%m-%d") from Limits where
limit_name='expiration' and id=a.limits_id) as dom_expire, (select
(value / 1048576) from Limits where limit_name='disk_space' and
id=a.limits_id) as Dom_Package, round((a.real_size / 1048576)) as
Dom_usage from domains a, clients b where (select
FROM_UNIXTIME(value,"%Y-%m-%d") from Limits where
limit_name='expiration' and id=a.limits_id and
(FROM_UNIXTIME(value,"%Y-%m-%d") between '2011-08-01' and
'2011-12-01') ) and a.cl_id=b.id group by a.id;
this all comes in a single line
in that i want to replace the date part alone in this format
between '2011-08-01' and '2011-12-01'
The script runs every friday , suppose if i run this on 10th month means.
the script need to change the value in the file like this
between '2011-09-01' and '2012-01-01'
every time the month alone need to change in this format
between 'current month -1month' and 'current month + 3 months'
sed -i 's/between '2011-08-01' and '2011-12-01'/'between '$(date --date="- 1 month" +%Y-%m)-01' and '$(date --date="+ 3 months" +%Y-%m)-01'/g file1
in this code iam trying to find and replace
but it shows this error
sed: -e expression #1, char 44: unterminated `s' command
What mistake iam doing can any 1 explain?

The expression isn't properly quoted. You start with 's/... but end with ... /g. No quote there. This is what I ran and it worked fine:
sed -i "s/between '[0-9-]*' and '[0-9-]*'/between '$(date --date'-1month' +%Y-%m-01)' and '$(date --date'+3months' +%Y-%m-01)'/g" file1

Related

how to replace the first "9" in a string with another character in postgresql database column?

I have a column "pnum" in a "test" table.
I'd like to replace the leading "9" in pnum with "*" for every record.
testdb=# select * from test limit 5;
id name pnum
===========================================
1 jk 912312345
2 tt 9912333333
I would like the pnums to look like this:
id name pnum
===========================================
1 jk *12312345
2 tt *912333333
How would I do something like this in postgres?
EDIT 1:
I have tried something like this so far:
select id, name, '*' && substring(pnum FROM 2 FOR CHAR_LENGTH(pnum)-1 ) from test limit 3;
Also tried this:
select id, name, '*' || substring(pnum FROM 2 FOR CHAR_LENGTH(pnum)-1 ) from test limit 3;
Neither one has worked...
EDIT 2:
I figured it out:
select id, name, '*'::text || substring(pnum FROM 2 FOR CHAR_LENGTH(pnum)-1 ) from test limit 3;
See function regexp_replace(string text, pattern text, replacement text [, flags text]) String Functions and Operators
SELECT regexp_replace('9912333333', '^[9]', '*');
regexp_replace
----------------
*912333333
You can use Postgres' string manipulation functions for this. In your case "Substring" and "Char_Length"
'*' || Substring(<yourfield> FROM 2 FOR CHAR_LENGTH(<yourfield>)-1) as outputfield

How to replace captured group with evaluated expression (adding an integer value to capture group)

I need to convert some strings with this format:
B12F34
to something like that:
Building 12 - Floor 34
but I have to add a value, say 10, to the second capture group so the new string would be as:
Building 12 - Floor 44
I can use this postgres sentence to get almost everything done, but I don't know how to add the value to the second capture group.
SELECT regexp_replace('B12F34', 'B(\d+)F(\d+)', 'Building \1 - Floor \2', 'g');
I have been searching for a way to add a value to \2 but all I have found is that I can use 'E'-modifier, and then \1 and \2 need to be \\1 and \\2:
SELECT regexp_replace('B12F34', 'B(\d+)F(\d+)', E'Building \\1 - Floor \\2', 'g')
I need some sentence like this one:
SELECT regexp_replace('B12F34', 'B(\d+)F(\d+)', E'Building \\1 - Floor \\2+10', 'g')
to get ........ Floor 44 instead of ........ Floor 34+10
You can not do this in regexp alone because regexp does not support math on captured groups even if they are all numeric characters. So you have to get the group that represents the floor number, do the math and splice it back in:
SELECT regexp_replace('B12F34', 'B(\d+)F(\d+)', 'Building \1 - Floor ') ||
((regexp_matches('B12F34', '[0-9]+$'))[1]::int + 10)::text;
Not very efficient because of the two regexp calls. Another option is to just get the two numbers in a sub-query and assemble the string in the main query:
SELECT format('Building %L - Floor %L', m.num[1], (m.num[2])::int + 10)
FROM (
SELECT regexp_matches('B12F34', '[0-9]+', 'g') AS num) m;

Complex sed Command for Insert Command

I have a bunch of php files, which have many insert commands.
In each query, I want to insert a column variable admin_id = '$admin_id',
i.e., if the query is
insert into users (ch_id, num_value) values ('2', '100')
the query should be converted to
insert into users (admin_id, ch_id, num_value) values ($admin_id, '2', '100')
To do this, I have executed the following command
sed -i 's/\(insert.*into.*\) (\(.*values\)/\1 (admin_id, \2/' *.php
and
sed -i "s/\(insert.*into.*\) values (/\1 values ('\$admin_id', /" *.php
The above has worked successfully, but am still facing problem with SQL queries where there is no where in the query, i.e.,
insert into abctable (id,no)
to
insert into tablename (admin_id, id, no)
and
insert into abctable select $column from $tableperiod
to
insert into abctable select $column from $tableperiod where admin_id='$admin_id'
and
insert into abctable select $column from $tableperiod where abc != 'xyz'
to
insert into abctable select $column from $tableperiod where admin_id = '$admin_id' and abc != 'xyz'
How can I insert admin_id in these queries as well?
The queries in php files are executed by passing the query to the function in the following way:
execute_query("insert * from $table order by username");
I can find the queries still which are left to be modified by
executing
grep 'execute_query' *| grep insert| grep -v admin_id > stillleft.txt
I have solved it by using the following command
sed -e "s/\(query.*insert.*select.*where\)/& admin_id='\$admin_id' and /g" -e t \
-e "s/\(query.*insert.*select.*\)\")/\1 where admin_id='\$admin_id\")'/g" -e t \
-e "s/\(query.*insert.*\)(\(.*\)values (/\1(admin_id, \2values ('\$admin_id', /g" -e t \
-e "s/\(query.*insert.*(\)/& admin_id, /g" \
-i *.php
I'm not sure my testcases are right, but I think this could help you:
I changed the first statement, because I think it's easier and it matches the first and the second command of YOUR sed
sed -i 's/\(insert into .* (\)\(.*) values (\)\(.*\)) /\1admin_id, \2\$admin_id, \3/' *.php
The second (the first you are looking for) should work with the following
sed -i 's/\(insert into .* (\)\(.*) \)/\1admin_id, \2/' *.php
And the last two should work with this:
sed -i "s/\(insert into \w* select \$column from \$tableperiod\)/\1 where admin_id='\$admin_id'/" *.php
I hope this works for you, if not, please send a little bit more test data, if tested the commands with the text of your question as input
I you use multiple sed commands, you'll traverse the complete file each time. You can do it in a single pass. Assuming an input file infile that looks like this:
insert into users (ch_id, num_value) values ('2', '100')
insert into abctable (id, no)
insert into abctable select $column from $tableperiod
insert into abctable select $column from $tableperiod where abc != 'xyz'
we can use the following sed script sedscr
/^insert into/ {
s/\(([^)]*)\)(.*)\(([^)]*)\)/(admin_id, \1)\2($admin_id, \3)/
s/^([^(]+)\(([^)]*)\)$/\1(admin_id, \2)/
/\(.*\)/! {
/where/s/$/ and admin_id ='$admin_id'/
/where/!s/$/ where admin_id='$admin_id'/
}
}
It does the following:
if a line starts with insert into, then
for all lines with two pairs of parentheses, insert admin_id in the the first one and $admin_id in the second one
for lines with one pair of parentheses at the end, insert admin_id
if there are no parentheses, then
if there is a "where" clause, append and admin_id = '$admin_id'
else append where admin_id='$admin_id'
This can be called as follows:
$ sed -rf sedscr infile
insert into users (admin_id, ch_id, num_value) values ($admin_id, '2', '100')
insert into abctable (admin_id, id, no)
insert into abctable select $column from $tableperiod where admin_id='$admin_id'
insert into abctable select $column from $tableperiod where abc != 'xyz' and admin_id ='$admin_id'
If you can't use extened regular expressions (-r), the quoting of parentheses has to be inverted (all \( become ( etc.) and the + has to be replaced by \{1,\}.
The cumbersome regexes such as \(([^)]*)\) stand for "between literal parentheses, capture zero or more characters that are not a closing parenthesis" – this enables non-greedy capturing.

Truncating leading zero from the string in postgresql

I'm trying to truncate leading zero from the address. example:
input
1 06TH ST
12 02ND AVE
123 001St CT
expected output
1 6TH ST
12 2ND AVE
123 1St CT
Here is what i have:
update table
set address = regexp_replace(address,'(0\d+(ST|ND|TH))','?????? need help here')
where address ~ '\s0\d+(ST|ND|TH)\s';
many thanks in advance
assuming that the address always has some number/letter address (1234, 1a, 33B) followed by a sequence of 1 or more spaces followed by the part you want to strip leading zeroes...
select substr(address, 1, strpos(address, ' ')) || ltrim(substr(address, strpos(address, ' ')), ' 0') from table;
or, to update the table:
update table set address = substr(address, 1, strpos(address, ' ')) || ltrim(substr(address, strpos(address, ' ')), ' 0');
-g
What you are looking for is the back references in the regular expressions:
UPDATE table
SET address = regexp_replace(address, '\m0+(\d+\w+)', '\1', 'g')
WHERE address ~ '\m0+(\d+\w+)'
Also:
\m used to match the beginning of a word (to avoid replacing inside words (f.ex. in 101Th)
0+ truncates all zeros (does not included in the capturing parenthesis)
\d+ used to capture the remaining numbers
\w+ used to capture the remaining word characters
a word caracter can be any alphanumeric character, and the underscore _.

Replacing using awk/sed

I have a SQL query:
update SCOTT.GLOBAL set DAY_LIGHT_SAVING_STARTS=TO_DATE('03/31/2013 02:00:00', 'MM/DD/YYYY HH24:MI:SS'), DAY_LIGHT_SAVING_ENDS=TO_DATE('10/27/2011 02:00:00', 'MM/DD/YYYY HH24:MI:SS') where zone='GMT';
I want to replace every occurance of TO_DATE with a random number/string and also want the correcponding TO_DATE and random number/string to be saved in a file.
For example:
update SCOTT.GLOBAL set DAY_LIGHT_SAVING_STARTS=abc, DAY_LIGHT_SAVING_ENDS=pqr where zone='GMT';
File:
TO_DATE('03/31/2013 02:00:00', 'MM/DD/YYYY HH24:MI:SS')~~~~abc
TO_DATE('10/27/2011 02:00:00', 'MM/DD/YYYY HH24:MI:SS')~~~~pqr
How can I achieve this with awk/sed/perl?
I have certainly tried something, though did not share with SO here. Apologies. Here is what I have tried:
perl -p -i -e "s/TO_DATE(.*?)\)/abc/g" my.out
This replaces the occurances of TO_DATE but I cannot figure how I can generate separate random numbers in same line for two different occurances of TO_DATE, and save them to the file along with the corresponding TO_DATE clause.
If I understood well your needs you can try in bash something like bellow:
while read x; do
while [[ $x =~ TO_DATE\([^\)]+\) ]]; do
rand=$(dd if=/dev/urandom bs=3 count=1 2>/dev/null|base64)
x=${x/$BASH_REMATCH/$rand}
done
echo $x
done<<XXX
update SCOTT.GLOBAL set DAY_LIGHT_SAVING_STARTS=TO_DATE('03/31/2013 02:00:00', 'MM/DD/YYYY HH24:MI:SS'), DAY_LIGHT_SAVING_ENDS=TO_DATE('10/27/2011 02:00:00', 'MM/DD/YYYY HH24:MI:SS') where zone='GMT';
XXX
Output
update SCOTT.GLOBAL set DAY_LIGHT_SAVING_STARTS=YsuW, DAY_LIGHT_SAVING_ENDS=5Vve where zone='GMT';
This read every lines from a file (which is replaced by a here-is-the-document here). If the line matches with the TO_DATE\([^\)]+\) pattern it creates a semi-random string from the matching proportion reading /dev/urandom and replaces the found string with this encrypted string. Because of base64 the bs in dd always should be multiple of 3 to avoid the = character from the end. It only works if the + and / is acceptable in the random string.