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; wcstring substr;
loc = wcstring_tok(buff, (vars_left() > 1) ? opts.delimiter : wcstring(), loc); loc = wcstring_tok(buff, (vars_left() > 1) ? opts.delimiter : wcstring(), loc);
if (loc.first != wcstring::npos) { 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); substr = wcstring(buff, loc.first, loc.second);
} }
vars.set_one(*var_ptr++, opts.place, substr); vars.set_one(*var_ptr++, opts.place, substr);

View File

@ -12,3 +12,11 @@ set -l
# CHECK: a 'afoo barb' # CHECK: a 'afoo barb'
# CHECK: b # CHECK: b
# CHECK: c # 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 '' 1 '' 1 ''
1 'test' 1 '' 1 '' 1 'test' 1 '' 1 ''
1 'foo' 1 'bar' 1 ' baz' 1 'foo' 1 'bar' 1 'baz'
0 a 0 a
#################### ####################
@ -129,6 +129,6 @@ c
Multi-char delimiters with IFS Multi-char delimiters with IFS
a a
b b
..c c
banana sausage banana sausage