-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Description
Observed behaviour
When read reads N variables from a string that holds N+1 variables if split by $IFS, variable number N will contain excess whitespace if more than one blank is separating the words.
E.g.: After Reading the string "A<space><tab><space>B<space><tab><space>C" into variables $A and $REST, $REST will contain "<tab><space>B<space><tab><space>C".
Expected behaviour
After Reading the string "A<space><tab><space>B<space><tab><space>C" into variables $A and $REST, $REST should contain "B<space><tab><space>C".
Relevant parts of read(1) says:
If no option to determine how to split like --delimiter, --line or
--tokenize is given, the variable IFS is used as a list of characters
to split on. Relying on the use of IFS is deprecated and this behaviour
will be removed in future versions.
and
If there are more tokens than variables, the complete remainder is
assigned to the last variable.
While I can see how the “the use of IFS is deprecated” and “the complete remainder” can be interpreted in more than one way, skipping all blanks and only putting "word<blank(s)>word" in the last variable is consistent with how a number of other shells – notably bash, dash, ksh, mksh, posh, sh, yash and zsh – are splitting a string into a number of words, and if fish's behaviour is intentional, I fail to see the logic or usefulness.
Examples
fish
$ cat read-test.fish
#!/bin/sh
# run with fish
# A<space><tab><space>B<space><tab><space>C
set TEST (printf 'A \t B \t C')
printf 'TEST="%s"\n' "$TEST"
# Assert that length of TEST is 1+3+1+3+1=9
printf 'len(TEST)=%s\n' (string length "$TEST")
# Let's read A into variable A and the rest into variable REST
echo "$TEST" \
| while read A REST
printf 'A="%s"\n' "$A"
printf 'REST="%s"\n' "$REST"
printf 'len(REST)=%s\n' (string length "$REST")
end
:
# eof
$ fish read-test.fish
TEST="A B C"
len(TEST)=9
A="A"
REST=" B C"
len(REST)=7bash et al.
$ cat read-test.sh
#!/bin/sh
# run with bash, dash, ksh, mksh, posh, sh, yash, zsh
# A<space><tab><space>B<space><tab><space>C
TEST=$(printf 'A \t B \t C')
printf 'TEST="%s"\n' "$TEST"
# Assert that length of TEST is 1+3+1+3+1=9
printf 'len(TEST)=%s\n' "${#TEST}"
# Let's read A into variable A and the rest into variable REST
echo "$TEST" \
| while read A REST
do
printf 'A="%s"\n' "$A"
printf 'REST="%s"\n' "$REST"
printf 'len(REST)=%s\n' "${#REST}"
done
:
# eof
$ bash read-test.sh
TEST="A B C"
len(TEST)=9
A="A"
REST="B C"
len(REST)=5Version(s)
$ fish --version
fish, version 3.0.2-1939-gea7868988
$ uname -a
Linux brainfreeze 5.4.2-arch1-1 #1 SMP PREEMPT Thu, 05 Dec 2019 12:29:40 +0000 x86_64 GNU/Linux
$ echo $TERM
xterm-256color- GNU bash, version 5.0.11(1)-release (x86_64-pc-linux-gnu)
- dash 0.5.10.2
- ksh 2020.0.0
- mksh 57
- posh 0.13.2
- yash 2.49
- zsh 5.7.1