4

sed removing everything until and including the first period if there is more than one period on that line and do this for the whole file.

Before sed:

akamai.com
cdnjs.cloudflare.com
com.cdn.cloudflare.net

After sed:

akamai.com
cloudflare.com
cdn.cloudflare.net
12
$ sed '/\..*\./s/^[^.]*\.//' file
akamai.com
cloudflare.com
cdn.cloudflare.net

The sed script first matches lines that contain at least two dots using the regular expression \..*\. (could also have been written [.].*[.]). For lines matching this, a substitution that removes everything up to and including the first dot is performed.

Using awk, being somewhat long-winded in comparison to the above:

$ awk -F '.' -vOFS='.' 'NF > 2 { n=split($0, a); $0=""; for (i=2;i<=n;++i) $(NF+1)=a[i] } 1' file
akamai.com
cloudflare.com
cdn.cloudflare.net

Here, whenever there are more than two dot-delimited fields, we split the current line on dots, and then re-create the current record from that, skipping the first field. The trailing 1 at the end causes every line (modified or not) to be printed.

Shorter awk in the same fashion as the sed solution:

$ awk -F '.' 'NF > 2 { sub("^[^.]*\.", "") } 1' file
akamai.com
cloudflare.com
cdn.cloudflare.net
  • It is possible to use only one regex in sed: sed '/\.\([^.]*\.\)/s//\1/' infile and the awk could be a lot smaller: awk '$0~re{sub(/^[^.]*\./,"")}1' re='^[^.]*\\.([^.]*\\.)' infile – Isaac Jul 27 '18 at 21:03
  • Grep gets a bit complex: grep -P '^(?=[^.]*\.[^.]*\.)[^.]*\.\K.*|.*' infile – Isaac Jul 27 '18 at 21:21
1

You could approach this using the following methods:

perl -lpe '$_ = $1 if /\.(.*\..*)/' input-file.txt

wherein, we rely on a regex that zeroes in on a dot . character that can see another dot to it's right. Then whatever is to the right is captured and made available in $1 and stuffed inside the current line. The -p option to Perl then takes this to the stdout as well as the one that didn't match as well.


perl -F\\. -pale '$_ = join ".", splice @F, 1 if @F > 2' input.txt
  • Input file is read line-by-line via the -p option and autoprint is also turned on via this option as well.

  • Each record is split on the dot . and the individual fields stored in the array @F indexed starting from 0 via the -a option.

  • -l option makes RS = ORS = "\n"

  • Only when we have more than 2 elements in the array @F, meaning there were atleast 2 dots in the current record, we select such a record for modifications.

  • For such a record, the splice @F, 1 function strips away elements 2nd onwards and presents them to the join function which then joins them using the dot character, this then is stuffed inside the $_ , aka, current record.

  • The -p option then takes this modified current record to the stdout. The one that didnot modify is anyway taken silently to the stdout.


Using GNU sed we can also do the task without taking recourse of capturing parens:

sed -e 
    s/\./\n/2;T
    y/\n./.\n/
    s/\n/./2g
    s/.*\n//
' input.file

Output:

akamai.com
cloudflare.com
cdn.cloudflare.net

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.