How to remove tags before dot in classes?

Viewed 104

A file has following list:

abc.class1 def.class2 ghi.class1.class2 .class1.class2 
abc.class3 def.class4 ghi.class3.class4 .class3.class4

expected output:

.class1 .class2 .class1.class2 .class1.class2
.class3 .class4 .class3.class4 .class3.class4

Using following sed command

sed 's/^.*\././g' 

gives

output:
.class2
8 Answers

Your ^.*\. pattern matches a part of a string from the start till the last occurrence of a literal . in the string, so in the end, this whole part of a line is removed (together with a dot).

You can use

#!/bin/bash
s='abc.class1 def.class2 ghi.class1.class2 .class1.class2 
abc.class3 def.class4 ghi.class3.class4 .class3.class4'
sed -E 's/( |^)[^ .]+\./\1./g'  <<< "$s"

See the online demo. The POSIX ERE regex matches

  • ( |^) - Group 1 (\1): a space or start of string
  • [^ .]+ - one or more chars other than space and dot
  • \. - a literal . char.

Each match is replaced with Group 1 value + ..

You can use awk to trim the strings field by field if they don't start with .:

awk '{for (i=1;i<=NF;i++) sub(/^[^.]*\./,".",$i)} 1' file
.class1 .class2 .class1.class2 .class1.class2
.class3 .class4 .class3.class4 .class3.class4

An awk approach using match and substr

awk '{for(i=1;i<=NF;i++){match($i,"\.c"); $i=substr($i,RSTART,length($i))}}1' file
.class1 .class2 .class1.class2 .class1.class2
.class3 .class4 .class3.class4 .class3.class4

With a sed that has -E for EREs, e.g. GNU or BSD seds:

$ sed -E 's/(^| )[^.]+/\1/g' file
.class1 .class2 .class1.class2 .class1.class2
.class3 .class4 .class3.class4 .class3.class4

otherwise with any sed:

$ sed 's/^[^.]*//; s/ [^.]*/ /g' file
.class1 .class2 .class1.class2 .class1.class2
.class3 .class4 .class3.class4 .class3.class4

Using sed

$ sed 's/[^.]*\(\.[^ ]* \)/\1/g' input_file
.class1 .class2 .class1.class2 .class1.class2
.class3 .class4 .class3.class4 .class3.class4

I would harness GNU AWK for this task following way, let file.txt content be

abc.class1 def.class2 ghi.class1.class2 .class1.class2 
abc.class3 def.class4 ghi.class3.class4 .class3.class4

then

awk 'BEGIN{FPAT="\\.[^ ]*"}{$1=$1;print}' file.txt

output

.class1 .class2 .class1.class2 .class1.class2
.class3 .class4 .class3.class4 .class3.class4

Explanation: use FPAT (field pattern) to inform AWK that field is literal . followed by zero or more non-spaces. $1=$1 triggers line rebuild, print does print said line.

(tested in GNU Awk 5.0.1)

gawk -F. -v OFS=. -v RS='[[:space:]]' '{ $1 = ""; printf "%s", $0 RT }' file

Using awk with gsub() function:

awk '{gsub(/[[:alpha:]]+\./,".")} 1' file
.class1 .class2 .class1.class2 .class1.class2
.class3 .class4 .class3.class4 .class3.class4
  • or GNU awk gensub() function:
awk '{print gensub(/[[:alpha:]]+\./,".","g")}' file
.class1 .class2 .class1.class2 .class1.class2
.class3 .class4 .class3.class4 .class3.class4
Related