skip to Main Content

I have this shell script

#/bin/bash
SUB_DOMAIN="test.google.com"
IFS=. read -ra __ <<< "${SUB_DOMAIN}"
IFS=. eval 'DOMAIN="${__[*]:(-2)}"'
echo "${DOMAIN} - ${SUB_DOMAIN}"

If I run it under Debian, everything works. But if I start it in a minimal Docker Linux (alpha), I get the following error. Do I have to install anything else there?

line 3: syntax error: unexpected redirection

3

Answers


  1. Most probably you do not have bash installed and you are running your script in posix shell. The here string <<< is a bash extension. And bash arrays (and thus expanding arr[*]) and read -a are also bash extensions.

    Do I have to install anything else there?

    Yes, actually install bash and then run your script in bash.

    Anyway I suggest knowing the environment you are writing for, do not use specific extensions if you want your script to be portable to environments without bash and maybe use a more posix friendly (but I think more resource consuming) alternative:

    SUB_DOMAIN="test.google.com"
    DOMAIN=$(printf "%sn" "$SUB_DOMAIN" | rev | cut -d. -f-2 | rev)
    

    And remember that eval is evil – a malicious input like SUB_DOMAIN="test.$(rm -irf /).com" may cause havoc on that eval line.

    Login or Signup to reply.
  2. Do it with POSIX shell grammar and it should be good everywhere:

    #!/usr/bin/env sh
    
    SUB_DOMAIN="test.google.com"
    DOMAIN="${SUB_DOMAIN#*.}"
    echo "${DOMAIN} - ${SUB_DOMAIN}"
    
    Login or Signup to reply.
  3. You said in a comment:

    My goal is actually to separate a string at the points and get the last two values.

    The sed(1) tool can do this straightforwardly. If you look at the input string as

       text     period  non-periods  period  non-periods  end
    foo.bar.baz    .      google        .        com
    

    You can translate this into regular expression syntax: . is any single text character, . is specifically a period, [^.] is anything but a period, x* is any number of x, and $ is end of string. Parentheses (...) (in "classic" regexps) mark a group that you’ll want to retrieve later. So you can construct a regexp that matches this string, marking the domain part as a capture group:

       text     period  non-periods  period  non-periods  end
        .*         . (  [^.]*        .       [^.]*   ) $
    

    Then you can use sed to replace strings matching this regexp with 1, the contents of the matching group.

    #!/bin/sh
    SUB_DOMAIN="test.google.com"
    DOMAIN=$(echo "$SUB_DOMAIN" | sed 's/.*.([^.]*.[^.]*)$/1/')
    echo "$DOMAIN - $SUB_DOMAIN"
    

    This will work whenever the POSIX toolset is available, including minimal environments like Alpine containers. It doesn’t depend on any particular shell extensions.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search