Trim trailing newline on cmdsubst when IFS=''

When $IFS is empty, command substitution no longer splits on newlines.
However we still want to trim off a single trailing newline, as most
commands will emit a trailing newline and it makes it harder to work
with their output.
This commit is contained in:
Kevin Ballard 2014-08-28 18:27:23 -07:00
parent cc52a59e1a
commit 7fce9e2411
3 changed files with 43 additions and 16 deletions

View file

@ -1540,7 +1540,7 @@ static int exec_subshell_internal(const wcstring &cmd, wcstring_list_t *lst, boo
ASSERT_IS_MAIN_THREAD(); ASSERT_IS_MAIN_THREAD();
int prev_subshell = is_subshell; int prev_subshell = is_subshell;
const int prev_status = proc_get_last_status(); const int prev_status = proc_get_last_status();
char sep=0; bool split_output=false;
//fprintf(stderr, "subcmd %ls\n", cmd.c_str()); //fprintf(stderr, "subcmd %ls\n", cmd.c_str());
@ -1548,7 +1548,7 @@ static int exec_subshell_internal(const wcstring &cmd, wcstring_list_t *lst, boo
if (! ifs.missing_or_empty()) if (! ifs.missing_or_empty())
{ {
sep = '\n'; split_output=true;
} }
is_subshell=1; is_subshell=1;
@ -1580,23 +1580,36 @@ static int exec_subshell_internal(const wcstring &cmd, wcstring_list_t *lst, boo
{ {
const char *begin = io_buffer->out_buffer_ptr(); const char *begin = io_buffer->out_buffer_ptr();
const char *end = begin + io_buffer->out_buffer_size(); const char *end = begin + io_buffer->out_buffer_size();
const char *cursor = begin; if (split_output)
while (cursor < end)
{ {
// Look for the next separator const char *cursor = begin;
const char *stop = (const char *)memchr(cursor, sep, end - cursor); while (cursor < end)
const bool hit_separator = (stop != NULL);
if (! hit_separator)
{ {
// If it's not found, just use the end // Look for the next separator
stop = end; const char *stop = (const char *)memchr(cursor, '\n', end - cursor);
} const bool hit_separator = (stop != NULL);
// Stop now points at the first character we do not want to copy if (! hit_separator)
const wcstring wc = str2wcstring(cursor, stop - cursor); {
lst->push_back(wc); // If it's not found, just use the end
stop = end;
}
// Stop now points at the first character we do not want to copy
const wcstring wc = str2wcstring(cursor, stop - cursor);
lst->push_back(wc);
// If we hit a separator, skip over it; otherwise we're at the end // If we hit a separator, skip over it; otherwise we're at the end
cursor = stop + (hit_separator ? 1 : 0); cursor = stop + (hit_separator ? 1 : 0);
}
}
else
{
// we're not splitting output, but we still want to trim off a trailing newline
if (end != begin && end[-1] == '\n')
{
--end;
}
const wcstring wc = str2wcstring(begin, end - begin);
lst->push_back(wc);
} }
} }

View file

@ -7,6 +7,11 @@ set -l IFS \t
count (echo one\ntwo) count (echo one\ntwo)
set -l IFS set -l IFS
count (echo one\ntwo) count (echo one\ntwo)
echo [(echo -n one\ntwo)]
count (echo one\ntwo\n)
echo [(echo -n one\ntwo\n)]
count (echo one\ntwo\n\n)
echo [(echo -n one\ntwo\n\n)]
set -le IFS set -le IFS
function print_vars --no-scope-shadowing function print_vars --no-scope-shadowing

View file

@ -1,6 +1,15 @@
2 2
2 2
1 1
[one
two]
1
[one
two]
1
[one
two
]
1 'hello' 1 'there' 1 'hello' 1 'there'
1 'hello there' 1 'hello there'