BASH
input: cat test
1 a;b;c;d
2 a;b;c;d
3 a;b;c;d
desired output is:
1 a
1 b
1 c
1 d
2 a
2 b
2 c
Straightforward shell:
IFS=" ;"
shopt noglob # or set -f
while read -r line; do
set -- $line; a=$1; shift
for b; do printf '%s %s\n' "$a" "$b"; done
done
# if data never contains backslash can omit -r from read
# if data never contains glob patterns (? * [..] etc) can omit set -f
# if data never contains backslash and first col never begins with hyphen
# can replace printf with echo "$a" "$b"
Clever shell, if first column never contains percent or backslash:
IFS=" ;"
shopt noglob # or set -f
while read -r line; do
set -- $line; a=$1; shift
printf "$a %s\n" "$@"
done
# read -r and set -f as above
Both of these leave IFS and (maybe) noglob changed; if this is all or the last part of a script, or a function using (), those changes are to a local instance and discarded. Otherwise either explicitly save and restore, or surround with () so they are discarded.
Similarly both clobber the positional arguments, which generally matters only when in a script or function; if those are needed subsequently, save and restore them, or alternatively in bash or ksh only use a separate explicit array variable:
IFS=" ;"
shopt noglob # or set -f
while read -ra ary; do
a=${ary[0]}; unset ary[0]
for b in "${ary[@]}"; do printf '%s %s\n' "$a" "$b"; done
# or
printf "$a %s\n" "${ary[@]}"
done