diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index d568e81bd..992f7b6b3 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -362,6 +362,7 @@ maybe_t pipe_or_redir_t::from_string(const wchar_t *buff) { } case L'>': { consume(L'>'); + if (try_consume(L'>')) result.mode = redirection_mode_t::append; if (try_consume(L'|')) { // Note we differ from bash here. // Consider `echo foo 2>| bar` @@ -374,6 +375,7 @@ maybe_t pipe_or_redir_t::from_string(const wchar_t *buff) { : STDOUT_FILENO; // like >| } else if (try_consume(L'&')) { // This is a redirection to an fd. + // Note that we allow ">>&", but it's still just writing to the fd - "appending" to it doesn't make sense. result.mode = redirection_mode_t::fd; result.fd = has_fd ? parse_fd(fd_start, fd_end) // like 1>&2 : STDOUT_FILENO; // like >&2 @@ -381,11 +383,10 @@ maybe_t pipe_or_redir_t::from_string(const wchar_t *buff) { // This is a redirection to a file. result.fd = has_fd ? parse_fd(fd_start, fd_end) // like 1> file.txt : STDOUT_FILENO; // like > file.txt + if (result.mode != redirection_mode_t::append) result.mode = redirection_mode_t::overwrite; // Note 'echo abc >>? file' is valid: it means append and noclobber. // But here "noclobber" means the file must not exist, so appending // can be ignored. - result.mode = redirection_mode_t::overwrite; - if (try_consume(L'>')) result.mode = redirection_mode_t::append; if (try_consume(L'?')) result.mode = redirection_mode_t::noclob; } break; diff --git a/tests/checks/redirect.fish b/tests/checks/redirect.fish index 14bc3298c..d1cd61772 100644 --- a/tests/checks/redirect.fish +++ b/tests/checks/redirect.fish @@ -8,6 +8,11 @@ end outnerr 0 &| count #CHECK: 2 + +outnerr appendfd 2>>&1 +#CHECK: out appendfd +#CHECK: err appendfd + set -l tmpdir (mktemp -d) outnerr overwrite &>$tmpdir/file.txt cat $tmpdir/file.txt