sed search/replace with wildcard - bash

I'm trying to use sed to do a search/replace in a set of text files. Where the files contain lines like:
$table->char('widget_guid', 36)->index('widget_guid');
I'm looking to replace the char with guid and strip out the , 36, so the resulting line would look like
$table->guid('widget_guid')->index('widget_guid');
My effort,
sed -i 's/char(\('.*'), 36\)/guid\(\1\)/g' *create*.php
but nothing is being replaced
I've tested the expression using regexp101.com and that shows it should picking up the correct blocks, with the correct capture group
Any suggestions as to what I might be doing wrong? And how to achieve what I want?

You can use this sed:
sed -E 's/char(\([^,]*)[^)]*/guid\1/' file
$table->guid('widget_guid')->index('widget_guid');
Explanation:
char: Match string char
(: Start capture group #1
\(: Match literal (
[^,]*: Match 0 or more of any characters that are not comma
): End capture group #1
[^)]*: Match 0 or more of any characters that are not )
-E enables extended regex (ERE) instead of basix regex (BRE) in sed
\1 is back-reference of capture group #1

Following sed may help you in same.
sed 's/char/guid/;s/, [0-9]*//' Input_file
Output will be as follows.
$table->guid('widget_guid')->index('widget_guid');

Related

Use sed to comment out .env entry

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.

Insert character after pattern with character exclusion using sed

I have this string of file names.
FileNames="FileName1.txtStrange-File-Name2.txt.zipAnother-FileName.txt"
What I like to do is to separate the file names by semicolon so I can iterate over it. For the .zipextension I have a working command.
I tried the following:
FileNames="${FileNames//.zip/.zip;}"
echo "$FileNames" | sed 's|.txt[^.zip]|.txt;|g'
Which works partially. It add a semicolon to the .zip as expected, but where sed matches the .txt I got the output:
FileName1.txt;trange-File-Name2.txt.zip;Another-FileName.txt
I think because of the character exclusion sed replaces the following character after the match.
I would like to have an output like this:
FileName1.txt;Strange-File-Name2.txt.zip;Another-FileName.txt
I'm not sticked to sed, but it would be fine to using it.
There might be a better way, but you can do it with sed like this:
$ echo "FileName1.txtStrange-File-Name2.txt.zipAnother-FileName.txt" | sed 's/\(zip\|txt\)\([^.]\)/\1;\2/g'
FileName1.txt;Strange-File-Name2.txt.zip;Another-FileName.txt
Beware that [^.zip] matches 'one char that is not ., nor z, nor i nor p'. It does not match 'a word that is not .zip'
Note the less verbose solution by #sundeep:
sed -E 's/(zip|txt)([^.])/\1;\2/g'
sed -r 's/(\.[a-z]{3})(.)/\1;\2/g'
would be a more generic expression.

Replace content in a file or line matching a regular expression using SED

How to replace a line / part of a line in a file using SED command?
search_text_1_server=value.env_1.path_to_file
search_text_2_server=value.env_1.path_to_file
search_text_3_server=value.env_1.path_to_file
some_other_key=value.env_1.another_path
Now I want a sed command to find the lines which match the regular expression search_text_{any}_server and then replace env_1 with env_2
Found the regular expression to find the required lines.
^search_text_[a-z_]\*_server.*$
Now how to add the SED syntax to replace
PS : I am not an expert in shell
Your regex is close. You can use:
sed -E 's/^(search_text_[a-z_]*_server=.*)env_1\./\1env_2\./' file
search_text_1_server=value.env_2.path_to_file
search_text_2_server=value.env_2.path_to_file
search_text_3_server=value.env_2.path_to_file
some_other_key=value.env_1.another_path
Assuming country code to be two alphabets, you could do
sed -Ei 's/(search_text_[a-z]{2}_server=value\.)env_1/\1env_2/' file
should do it.
What's happening here
[a-z]{2} checks for two alphabets which make a country code
sed s command is for substitution -> s/pattern/replacement
() selects the matched regex pattern for reuse, Note \1 for reuse
-i is the inplace edit option of sed which makes changes permanent in the file

Ignoring lines with blank or space after character using sed

I am trying to use sed to extract some assignments being made in a text file. My text file looks like ...
color1=blue
color2=orange
name1.first=Ahmed
name2.first=Sam
name3.first=
name4.first=
name5.first=
name6.first=
Currently, I am using sed to print all the strings after the name#.first's ...
sed 's/name.*.first=//' file
But of course, this also prints all of the lines with no assignment ...
Ahmed
Sam
# I'm just putting this comment here to illustrate the extra carriage returns above; please ignore it
Is there any way I can get sed to ignore the lines with blank or whitespace only assignments and store this to an array? The number of assigned name#.first's is not known, nor are the number of assignments of each type in general.
This is a slight variation on sputnick's answer:
sed -n '/^name[0-9]\.first=\(.\+\)/ s//\1/p'
The first part (/^name[0-9]\.first=\(.\+\)/) selects the lines you want to pass to the s/// command. The empty pattern in the s command re-uses the previous regular expression and the replacement portion (\1) replaces the entire match with the contents of the first parenthesized part of the regex. Use the -n and p flags to control which lines are printed.
sed -n 's/^name[0-9]\.\w\+=\(\w\+\)/\1/p' file
Output
Ahmed
Sam
Explainations
the -n switch suppress the default behavior of sed : printing all lines
s/// is the skeleton for a substitution
^ match the beginning of a line
name literal string
[0-9] a digit alone
\.\w\+ a literal dot (without backslash means any character) followed by a word character [a-zA-Z0-9_] al least one : \+
( ) is a capturing group and \1 is the captured group

Explained shell statement

The following statement will remove line numbers in a txt file:
cat withLineNumbers.txt | sed 's/^.......//' >> withoutLineNumbers.txt
The input file is created with the following statement (this one i understand):
nl -ba input.txt >> withLineNumbers.txt
I know the functionality of cat and i know the output is written to the 'withoutLineNumbers.txt' file. But the part of '| sed 's/^.......//'' is not really clear to me.
Thanks for your time.
That sed regular expression simply removes the first 7 characters from each line. The regular expression ^....... says "Any 7 characters at the beginning of the line." The sed argument s/^.......// substitutes the above regular expression with an empty string.
Refer to the sed(1) man page for more information.
that sed statement says the delete the first 7 characters. a dot "." means any character. There is an even easier way to do this
awk '{print $2}' withLineNumbers.txt
you just have to print out the 2nd column using awk. No need to use regex
if your data has spaces,
awk '{$1="";print substr($0,2)}' withLineNumbers.txt
sed is doing a search and replace. The 's' means search, the next character ('/') is the seperator, the search expression is '^.......', and the replace expression is an empty string (i.e. everything between the last two slashes).
The search is a regular expression. The '^' means match start of line. Each '.' means match any character. So the search expression matches the first 7 characters of each line. This is then replaced with an empty string. So what sed is doing is removing the first 7 characters of each line.
A more simple way to achieve the same think could be:
cut -b8- withLineNumbers.txt > withoutLineNumbers.txt

Resources