Unix- Sed replacing substring - unix

I am new to sed . I want to replace a substring
for example:
var1=server1:game1,server2:game2,sever3:game1
output should be
server1 server2 server3 (with just spaces)
I have tried this.
echo $var1 | sed 's/,/ /g' | sed 's/:* / /g'
This is not working. Please suggest a solution.

You can try this sed,
echo $var1 | sed 's/:[^,]\+,\?/ /g'
Explanation:
:[^,]\+, - It will match the string from : to ,
\? - Previous may occur or may not ( Since end of line don't have , )

echo $var1 | sed s/:game[0-9],*/\ /
Assuming your sub string has game followed by a number([0-9]*)

An awk variation using same regex as sed
awk '{gsub(/:[^,]+,?/," ")}1' <<< "$var1"
PS Its always good custom to "quote" variables

Just for info, you are really only matching, not replacing, so grep can be your friend (with -P):
grep -oP '[^:,=]+(?=:)'
That matches a number of characters that aren't :,= followed by a : using lookahead.
This will put the servers on different lines, which may be what you want anyway. You can put them on one line by adding tr:
grep -oP '[^:,=]+(?=:)' | tr '\n' ' '

Related

Surround every line with single quote except empty lines

My goal is to add a single apostrophe to every line in the file and skip empty lines.
file.txt:
Quote1
Quote2
Quote3
So far I have used sed:
sed -e "s/\(.*\)/'\1'/"
Which does the job but creates apostrophes also in empty lines:
'Quote1'
'Quote2'
''
'Quote3'
My goal:
'Quote1'
'Quote2'
'Quote3'
How could I achieve this by using sed, or maybe it should it be awk.
.* means zero or more characters, you want 1 or more characters which in any sed would be ..*:
$ sed "s/..*/'&'/" file
'Quote1'
'Quote2'
'Quote3'
You can also write that regexp as .\+ in GNU sed, .\{1,\} in POSIX seds, and .+ in GNU or OSX/BSD sed when invoked with -E.
The above assumes lines of all blanks should be quoted. If that's wrong then:
$ sed "s/.*[^[:blank:]].*/'&'/" file
'Quote1'
'Quote2'
'Quote3'
In any awk assuming lines of all blanks should be quoted:
$ awk '/./{$0="\047" $0 "\047"}1' file
'Quote1'
'Quote2'
'Quote3'
otherwise:
$ awk 'NF{$0="\047" $0 "\047"}1' file
'Quote1'
'Quote2'
'Quote3'
You can see the difference between the above with this:
$ printf ' \n' | sed "s/..*/'&'/"
' '
$ printf ' \n' | sed "s/.*[^[:blank:]].*/'&'/"
$ printf ' \n' | awk '/./{$0="\047" $0 "\047"}1'
' '
$ printf ' \n' | awk 'NF{$0="\047" $0 "\047"}1'
$
One way:
awk '$1{$0 = q $0 q}1' q="'" file
Add quotes only if 1st column($1) has some value. 1 to print every line.
Assuming you want to add the single quotes to lines that contain nothing but whitespace:
sed -E "/./s/(.*)/'\1'/"
Another sed
sed '/^$/!{s/^/\x27/;s/$/\x27/}' file
The above script says
Look for an empty line - /^$/ - pattern.
For those lines that doesn't follow the above pattern(!), substitute start(^) and end($) with single quotes(\x27).
You can use perl to check for a negative lookbehind, asserting that you won't match an "empty" line:
perl -pe 's/(?<!$)(.*)/"\1"/' file
Another alternative is being more specific in your regex, as #edmorton suggested in his answer.
tried on gnu sed
sed -E "s/\S+/'&'/" file.txt

Sed command garbled on Solaris [duplicate]

I have this data in file.txt:
1234-abca-dgdsf-kds-2;abc dfsfds 2
123-abcdegfs-sdsd;dsfdsf dfd f
12523-cvjbsvndv-dvd-dvdv;dsfdsfpage
I want to replace the string after "-" and up to ";" with just ";", so that I get:
1234;abc dfsfds 2
123;dsfdsf dfd f
12523;dsfdsfpage
I tried with the command:
sed -e "s/-.*;/;" file.txt
But it gives me the following error:
sed command garbled
Why is this happening?
sed replacement commands are defined as (source):
's/REGEXP/REPLACEMENT/[FLAGS]'
(substitute) Match the regular-expression against the content of the pattern space. If found, replace matched string with REPLACEMENT.
However, you are saying:
sed "s/-.*;/;"
That is:
sed "s/REGEXP/REPLACEMENT"
And hence missing a "/" at the end of the expression. Just add it to have:
sed "s/-.*;/;/"
# ^
You are missing a slash at the end of the sed command:
Should be "s/-.*;/;/"
-.* here the * greedy, so this would fail if there are more than one ;
echo "12523-cvjbsvndv-dvd-dvdv;dsfdsfpage;test" | sed -e "s/-.*;/;/"
12523;test
Change to -[^;]*
echo "12523-cvjbsvndv-dvd-dvdv;dsfdsfpage;test" | sed -e "s/-[^;]*;/;/"
12523;dsfdsfpage;test
This should work :
sed 's/-.*;/;/g' file > newFile

Split line with multiple delimiters in Unix

I have the below lines in a file
id=1234,name=abcd,age=76
id=4323,name=asdasd,age=43
except that the real file has many more tag=value fields on each line.
I want the final output to be like
id,name,age
1234,abcd,76
4323,asdasd,43
I want all values before (left of) the = to come out as separated with a , as the first row and all values after the (right side) of the = to come below for in each line
Is there a way to do it with awk or sed? Please let me know if for loop is required for the same?
I am working on Solaris 10; the local sed is not GNU sed (so there is no -r option, nor -E).
$ cat tst.awk
BEGIN { FS="[,=]"; OFS="," }
NR==1 {
for (i=1;i<NF;i+=2) {
printf "%s%s", $i, (i<(NF-1) ? OFS : ORS)
}
}
{
for (i=2;i<=NF;i+=2) {
printf "%s%s", $i, (i<NF ? OFS : ORS)
}
}
$ awk -f tst.awk file
id,name,age
1234,abcd,76
4323,asdasd,43
Assuming they don't really exist in your input, I removed the ...s etc. that were cluttering up your example before running the above. If that stuff really does exist in your input, clarify how you want the text "(n number of fields)" to be identified and removed (string match? position on line? something else?).
EDIT: since you like the brevity of the cat|head|sed; cat|sed approach posted in another answer, here's the equivalent in awk:
$ awk 'NR==1{h=$0;gsub(/=[^,]+/,"",h);print h} {gsub(/[^,]+=/,"")} 1' file
id,name,age
1234,abcd,76
4323,asdasd,43
FILE=yourfile.txt
# first line (header)
cat "$FILE" | head -n 1 | sed -r "s/=[^,]+//g"
# other lines (data)
cat "$FILE" | sed -r "s/[^,]+=//g"
sed -r '1 s/^/id,name,age\n/;s/id=|name=|age=//g' my_file
edit: or use
sed '1 s/^/id,name,age\n/;s/id=\|name=\|age=//g'
output
id,name,age
1234,abcd,76 ...(n number of fields)
4323,asdasd,43...
The following simply combines the best of the sed-based answers so far, showing you can have your cake and eat it too. If your sed does not support the -r option, chances are that -E will do the trick; all else failing, one can replace R+ by RR* where R is [^,]
sed -r '1s/=[^,]+//g; s/[^,]+=//g'
(That is, the portable incantation would be:
sed "1s/=[^,][^,]*//g; s/[^,][^,]*=//g"
)

Update value within a unix flat file

Kindly help. I want to make .0 to be 0.0 within a UNIX file yyyyy.csv :
603905209;47.824;USD
603905477;57.199;USD
603938657;3.2281;USD
603949388;.00191;USD
603937274;.00563;USD
603911160;.00287;USD
I want the result to be
603905209;47.824;USD
603905477;57.199;USD
603938657;3.2281;USD
603949388;0.00191;USD
603937274;0.00563;USD
603911160;0.00287;USD
but I got this result:
603905209;0.4.7824;USD
603905477;0.5.7199;USD
603938657;0.3.2281;USD
603949388;0.00191;USD
603937274;0.00563;USD
603911160;0.00287;USD
Below is my command:
sed 's/;.0/;0.0/g' yyyyy.csv | sed 's/;.2/;0.2/g' | sed 's/;.1/;0.1/g' | sed 's/;.3/;0.3/g' | sed 's/;.4/;0.4/g' | sed 's/;.5/;0.5/g'| sed 's/;.6/;0.6/g' | sed 's/;.7/;0.7/g' | sed 's/;.8/;0.8/g' | sed 's/;.9/;0.9/g' > xxxxx.csv
You need to escape all the dots present in your regex or otherwise it would match any character. That is, . is a special meta character in regex which matches any character. To match a literal dot, you need to escape the ..
sed 's/;\.0/;0.0/g' yyyyy.csv
And this would be enough.
$ sed 's/;\.\([0-9]\)/;0.\1/g' file
603905477;57.199;USD
603938657;3.2281;USD
603949388;0.00191;USD
603937274;0.00563;USD
603911160;0.00287;USD
In basic sed, \(...\) called capturing group, which is used to capture the characters matched by the pattern present inside that group. So the pattern present inside the group is [0-9] which matches a digit from 0-9. We could refer the captured characters through back-referencing ie, \1. \1 at the replacement part refers to the characters which are present inside the group index 1.
Change your command to:
sed 's/;\./;0./g' File
i.e, just substitute ;. with ;0..
Just print your file using a tool that understands numbers:
$ awk -F';' '{printf "%d;%f;%s\n", $1,$2,$3}' file
603905209;47.824000;USD
603905477;57.199000;USD
603938657;3.228100;USD
603949388;0.001910;USD
603937274;0.005630;USD
603911160;0.002870;USD
awk -F';' '{printf "%d;%.5f;%s\n", $1,$2,$3}' file
603905209;47.82400;USD
603905477;57.19900;USD
603938657;3.22810;USD
603949388;0.00191;USD
603937274;0.00563;USD
603911160;0.00287;USD
$ awk -F';' '{printf "%d;%.2f;%s\n", $1,$2,$3}' file
603905209;47.82;USD
603905477;57.20;USD
603938657;3.23;USD
603949388;0.00;USD
603937274;0.01;USD
603911160;0.00;USD
Whatever precision you like...

In UNIX Terminal How to get a part of filename in a folder?

I have a list of n files in a folder have some format.
Eg: ABCD.EXXXX.ZZZZ.ZZZZZ.txt
in above file ABCD.E is common for all the files,ZZZZ.ZZZZ is user wish string and i need to extract XXXX from all the files , need to display distinct XXXX to user.. Is there any way to do so.? Help me out in doing so.. Thanks in advance..
Use ls -1 to make a list of the relevant files. Pipe it into sed to strip the beginning 'ABCD.E'. Then pipe it into sed again to remove everything after the first '.'
ls -1 ABCD\.E*\.txt | sed 's/^ABCD\.E//' | sed 's/\..*//'
Alternatively, if you want a little more control of the output you can do the second bit with awk
ls -1 ABCD\.E*\.txt | sed 's/^ABCD\.E//' | awk 'BEGIN{FS="."}{print "value =", $1, "user=", $2"."$3}'
awk -F"."'{print $2}' filename
You can try printing $1, $2 ,$3... to get more understanding of command.
You can use the bash/ksh parameter subsitution # and % for this from inside the shell.
function get_filename_section {
typeset f=${1:?}
typeset r=${f#ABCD.E}
print ${r%.ZZZZ.ZZZZZ.txt}
}
Testing:
[[ $( get_filename_section ABCD.EXXXX.ZZZZ.ZZZZZ.txt ) == XXXX ]] &&
echo ok || echo no

Resources