From: rofl0r Date: Thu, 18 Jun 2026 19:40:21 +0000 Subject: [PATCH] dash: fix redirect with fds > 9 When executing e.g. python3 999>debug.log, 999 wasn't recognized as an fd, but instead passed as a command line argument to python3. POSIX 2017 clearly states that file descriptors can be longer than a single digit: "The number n is an optional one or more digit decimal number designating the file descriptor number" https://pubs.opengroup.org/onlinepubs/9799919799/utilities/V3_chap02.html#tag_19_07 diff --git a/src/parser.c b/src/parser.c index 412e876..0e1e08e 100644 --- a/src/parser.c +++ b/src/parser.c @@ -621,9 +621,18 @@ void fixredir(union node *n, const char *text, int err) if (!err) n->ndup.vname = NULL; - if (is_digit(text[0]) && text[1] == '\0') - n->ndup.dupfd = digit_val(text[0]); - else if (text[0] == '-' && text[1] == '\0') + if (is_digit(text[0])) { + int fd = 0; + while (is_digit(*text)) { + fd *= 10; + fd += digit_val(*text++); + } + if (*text == '\0') { + n->ndup.dupfd = fd; + return; + } + } + if (text[0] == '-' && text[1] == '\0') n->ndup.dupfd = -1; else { @@ -1209,7 +1218,6 @@ endword: if (eofmark == NULL) { if ((c == '>' || c == '<') && quotef == 0 - && len <= 2 && (*out == '\0' || is_digit(*out))) { PARSEREDIR(); return lasttoken = TREDIR; @@ -1288,8 +1296,16 @@ more_heredoc: */ parseredir: { - char fd = *out; + char *p = out; union node *np; + int fd = -1; + + while (is_digit(*p) && len--) { + if (fd == -1) fd = 0; + else fd *= 10; + fd += digit_val(*p); + ++p; + } np = (union node *)stalloc(sizeof (struct nfile)); if (c == '>') { @@ -1338,8 +1354,7 @@ parseredir: { break; } } - if (fd != '\0') - np->nfile.fd = digit_val(fd); + if (fd != -1) np->nfile.fd = fd; redirnode = np; goto parseredir_return; } diff --git a/src/redir.c b/src/redir.c index e61d3da..a9601f2 100644 --- a/src/redir.c +++ b/src/redir.c @@ -146,7 +146,7 @@ redirect(union node *redir, int flags) if (fd == 0) reset_input(); - if (sv) { + if (sv && fd < 10) { int closed; p = &sv->renamed[fd];