3

I have a string -w o rd.
I need to split it to w o r d or to an array for 'w' 'o' 'r' 'd' it doesn't really matter.
I have tried the following

IFS='\0- ' read -a string <<< "-w o rd"  
echo ${string[*]}

rd isn't getting split. How can I make it get split

0

3 Answers 3

6

You can't use IFS in bash to split on nothing (it has to be on a character). There's no characters between r and d in rd. No space and no character isn't the same as the null character.

If you want each character as a separate element in the array, one way I can think of is to read each character individually and append it to an array (and using IFS to get rid of spaces and -):

bash-4.4$ while IFS=' -' read -n1 c ; do [[ -n $c ]] && foo+=("$c"); done <<<"-w o rd"
bash-4.4$ declare -p foo
declare -a foo=([0]="w" [1]="o" [2]="r" [3]="d")
2

You can remove the unwanted characters with ${var//pattern/replacement}:

s='-w o rd'
s=${s//[- ]}

And then use the substring expansion to pick one character at a time:

$ for ((i=0; i < ${#s}; i++)); do
      echo ${s:i:1};           # or do whatever you like here
  done

(it even seems to work with multi-byte characters, at least on my system.)


Note that IFS='\0- ' will assign a literal backslash to IFS as backslash has no special meaning within single quotes. The octal escape would work within $'...', but variables in Bash can't contain a NUL byte, so that doesn't help. (The string gets cut on the NUL, so e.g. x=$'foo\0bar'; printf "%q\n" "$x" prints just foo. Also, what @muru said, splitting on a NUL byte is not the same as splitting between every character)

1

If your string isn't too long:

w='-w o rd baa'
w=${w//[!a-z]}  # strip anything but lower case letters
eval echo '${w:'{0..10}':1}'
eval array=\( '${w:'{0..10}':1}' \)
echo "${array[@]}"

w o r d b a a

You can turn the silly thing into something nastier, IFS- and glob-safe and which takes into account the differences in the relative order of the brace and variable expansions between zsh, bash and ksh:

args(){ printf '<%s> ' "$@"; echo; }
w='-e a * () \n peek
    fo*"x'"'q"
eval eval args "'\"\${w:'{0..$((${#w}-1))}':1}\"'"
eval eval 'array=\(' "'\"\${w:'{0..$((${#w}-1))}':1}\"'" '\)'
args "${array[@]}"

<-> <e> < > <a> < > <*> < > <(> <)> < > <\> <n> < > <p> <e> <e> <k> <
> <     > <f> <o> <*> <"> <x> <'> <q>    

But franky, the only use of such monstrosity may be to scare off newbies and impress fools with assumed deep knowledge of shell language minutiae ;-)

You must log in to answer this question.

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