3

I'm trying to split a string in ash shell using only the tools provided in BusyBox.

The string is of the format host-name:port,host-name2:port2 but I only care about the first hostname and port, both of which I'd like access to as variables.

I've tried a few options I found on here but most pertain to bash and the equivalent commands/functionality doesn't seem to exist in ash shell.

Any ideas?

1
  • echo ${string%,*} Aug 21 '18 at 12:42
2

Beside an IFS solution, which has many side effects and limitations, a shell agnostic (for many shells) solution that works correctly with spaces, newlines, empty fields and divisors of several characters is:

#!/bin/sh

in='One-XX-X-17.0.0'

a=$in; div='-'; set --
while
    b=${a#*"$div"}
    set -- "$@" "${a%%"$div"*}"
    [ "$a" != "$b" ]
do
    a=$b
done
printf 'Element: %s\n' "$@"

#split 17.0.0 into NUM
a=$4; div='.'; set --
while
    b=${a#*"$div"}
    set -- "$@" "${a%%"$div"*}"
    [ "$a" != "$b" ]
do
    a=$b
done
printf 'Num: %s\n' "$@"

Which will print:

$ ./script
Element: One
Element: XX
Element: X
Element: 17.0.0
Num: 17
Num: 0
Num: 0
3
  • thank you, i took this for my first try until i realized, that with IFS you can do it without explicitly open-coding the splitting.
    – user56452
    Aug 10 '20 at 21:15
  • Using IFS has several corner cases and gotchas. Yes, it works, but only in some cases. @user56452
    – ImHere
    Aug 11 '20 at 1:34
  • works perfect in ash shell (/bin/sh) Oct 19 at 8:56
1

I came up for a similar problem (-> split the complete string into tokens) with this solution:

#!/bin/sh
input='host-name:port,host-name2:port2,One,XX X,192.178.88:999,17.0.0'
echo "input: $input"

OLDIFS=$IFS;IFS=,
for token in $input; do
    hostname=$(echo ${token%:*})
    port=$(echo ${token#*:})
    echo "hostname: $hostname, port: $port"
done
IFS=$OLDIFS

Which results in:

$ busybox ash bla.sh
input: host-name:port,host-name2:port2,One,XX X,192.178.88:999,17.0.0
hostname: host-name, port: port
hostname: host-name2, port: port2
hostname: One, port: One
hostname: XX X, port: XX X
hostname: 192.178.88, port: 999
hostname: 17.0.0, port: 17.0.0

For further reading you can dig into the man page (1) of ash (https://linux.die.net/man/1/ash ) and search for "IFS" and "Parameter Expansion".

CAVEAT: Do this only if you trust the input! See the comments below on things that can go wrong regarding file globbing and other stuff. This is a slick solution, if your input is somehow controlled. (-> I use it for a script where i know that immediatly after the input to the script will be changed, that testing will take place and any misconfiguration will immediatly be noticed. [Also nobody will ever do * or stuff in there ... hehe famous last words])

1
  • 2
    As $input must be unquoted for the shell split to work, you should disable the automatic globbing of some characters like * (try splitting one,*,two. In ash set -f will work. If the character to split is an space, repeated spaces are counted as one separator: try to split one two on spaces. Also, leading or trailing spaces (tabs or newlines) do not generate an empty element, try input=" one two ".
    – ImHere
    Aug 11 '20 at 1:32

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.