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, 2018 at 12:42

2 Answers 2

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, 2020 at 21:15
  • Using IFS has several corner cases and gotchas. Yes, it works, but only in some cases. @user56452
    – user232326
    Aug 11, 2020 at 1:34
  • works perfect in ash shell (/bin/sh) Oct 19, 2021 at 8:56
2

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 ".
    – user232326
    Aug 11, 2020 at 1:32

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .