Socowi's helpful answer offers an elegant bash
solution[1].
To complement it with a a portable, efficient sh
implementation that can also handle a variable number of spaces (and/or tabs) between the input words:
#!/bin/sh
# Input string.
string='word1 word2 word3 word4 word5 word6'
# Compress runs of multiple spaces (and/or tabs) between words, if any,
# to a single space.
string=$(printf '%s\n' "$string" | tr -s '[:blank:]' ' ')
# Count the number of words in the string.
# Note: On BSD/macOS, the result will have leading whitespace,
# but with operators such as `-le` inside `[ ... ]` and with
# *unquoted* references inside $(( ... )) that is not a problem.
wordCount=$(printf '%s\n' "$string" | wc -w)
start=1
while [ $start -le $wordCount ]; do
end=$start
while [ $end -le $wordCount ]; do
printf '%s\n' "$string" | cut -d ' ' -f "$start-$end"
end=$(( end + 1 ))
done
start=$(( start + 1 ))
done
[1] In bash
, splitting a string into the elements of an array with literals is safe, as long as you apply quoting to the the elements as needed:
Thus array=( word1 word2 word3 word4 word5 word6 )
works robustly (the elements don't need quoting), but array=( $str )
is not generally robust, because what $str
expands to is subject to globbing (and word-splitting, which, however, is desired here). The safe way to read the whitespace-separated tokens of a single-line string into an array is: read -ra array <<<"$str"