read: discard IFS delimiters before the last token

Do this only when splitting on IFS characters which usually contains
whitespace characters --- read --delimiter is unchanged; it still
consumes no more than one delimiter per variable. This seems better,
because it allows arbitrary delimiters in the last field.

Fixes #6406
This commit is contained in:
Johannes Altmanninger 2019-12-19 19:32:18 +01:00
parent 0531c02ce4
commit 1410f938aa
3 changed files with 18 additions and 2 deletions

View File

@ -608,6 +608,14 @@ int builtin_read(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
wcstring substr;
loc = wcstring_tok(buff, (vars_left() > 1) ? opts.delimiter : wcstring(), loc);
if (loc.first != wcstring::npos) {
if (vars_left() == 1) { // Discard trailing delimiters, see #6406
loc.first =
std::find_if(buff.begin() + loc.first, buff.end(),
[&opts](wchar_t c) {
return opts.delimiter.find(c) == wcstring::npos;
}) -
buff.begin();
}
substr = wcstring(buff, loc.first, loc.second);
}
vars.set_one(*var_ptr++, opts.place, substr);

View File

@ -12,3 +12,11 @@ set -l
# CHECK: a 'afoo barb'
# CHECK: b
# CHECK: c
echo "a b b" | read a b; string escape $a $b
# CHECK: a
# CHECK: 'b b'
echo 'a<><>b<>b' | read -d '<>' a b; printf %s\n $a $b
# CHECK: a
# CHECK: <>b<>b

View File

@ -27,7 +27,7 @@ two
1 ''
1 '' 1 ''
1 'test' 1 '' 1 ''
1 'foo' 1 'bar' 1 ' baz'
1 'foo' 1 'bar' 1 'baz'
0 a
####################
@ -129,6 +129,6 @@ c
Multi-char delimiters with IFS
a
b
..c
c
banana sausage