2

I have a string

VAR_A="127.0.0.1:12345"

I want to split it into HOSTNAME and PORT, with the delimiter :.

Per this post, I'm using this syntax to split the original VAR_A string:

HOSTNAME=${VAR_A%%:*}
PORT=${VAR_A#*:}

And it works if VAR_A if of the form xxxx:xxxx.

But I'd like to have the following result according to the value passed to VAR_A:

  • If VAR_A doesn't contain the char :, e.g. VAR_A=127.0.0.1, then HOSTNAME is assigned with 127.0.0.1, and assign empty string to PORT
  • If VAR_A contains the char : but nothing is after that :, e.g. VAR_A=127.0.0.1:, then same, HOSTNAME is assigned with 127.0.0.1, and assign empty string to PORT
  • If VAR_A contains the char : but nothing before that :, e.g. VAR_A=:12345, then assign empty string to HOSTNAME, and 12345 to PORT.

With current codes, if VAR_A=127.0.0.1, I got both HOSTNAME=127.0.0.1 and PORT=127.0.0.1, which is not desired.

If doable, I'd prefer a syntax similar to the one I provided -- the more succint/elegant the better.

IsaIkari
  • 1,002
  • 16
  • 31
  • Note: Bash and POSIX shell are two completely different shells. Since bash is included, presumably that is what is wanted. With POSIX shell you would want to use a utility like `awk` or `sed` (or perhaps `grep`). With bash, it has built-ins that will handle the parsing. – David C. Rankin Jan 05 '22 at 03:50

3 Answers3

2

You can remove the first part with another parameter expansion:

VAR_A=127.0.0.1

HOSTNAME=${VAR_A%%:*}
PORT=${VAR_A#"$HOSTNAME"}
PORT=${PORT#:}

If there is no newline in VAR_A:

IFS=: read -r HOSTNAME PORT <<< "$VAR_A"
2

How about a regex solution:

list=(127.0.0.1:12345 127.0.0.1 127.0.0.1: :12345)
for VAR_A in "${list[@]}"; do
    if [[ $VAR_A =~ ^([0-9.]*):?([0-9]*)$ ]]; then
        HOSTNAME=${BASH_REMATCH[1]}; PORT=${BASH_REMATCH[2]}
        printf "%-16s HOSTNAME=%-10s PORT=%-10s\n" "$VAR_A" "$HOSTNAME" "$PORT"
    fi
done

Output:

127.0.0.1:12345  HOSTNAME=127.0.0.1  PORT=12345
127.0.0.1        HOSTNAME=127.0.0.1  PORT=
127.0.0.1:       HOSTNAME=127.0.0.1  PORT=
:12345           HOSTNAME=           PORT=12345

Explanation of the regex ^([0-9.]*):?([0-9]*)$:

  • ^([0-9.]*) matches a zero or more length sequence of digits and/or dots at the beginning of $VAR_A. The matched substring is captured with ${BASH_REMATCH[1]}. The regex doesn't strictly validate the ipv4 address but will be enough for the purpose.
  • :? matches zero or one colon character.
  • ([0-9]*)$ matches a zero or more length sequence of digits at the end of $VAR_A. The matched substring is captured with ${BASH_REMATCH[2]}.
tshiono
  • 21,248
  • 2
  • 14
  • 22
-1

If this is for a bash script, you can use if..else statements just like any other programming language.

I'd recommend checking out this tutorial page and creating some type of script that first checks to see if your string has the : character, then performing further actions as needed (e.g. parsing the left/right halves as needed for the HOST and PORT).

This is just one approach, of course; there are plenty other ways to do this.

lawgik
  • 87
  • 3
  • 10