diff --git a/doc_src/cmds/read.rst b/doc_src/cmds/read.rst index 82c3f94a9..08093b431 100644 --- a/doc_src/cmds/read.rst +++ b/doc_src/cmds/read.rst @@ -25,7 +25,9 @@ The following options are available: - ``-s`` or ``--silent`` masks characters written to the terminal, replacing them with asterisks. This is useful for reading things like passwords or other sensitive information. -- ``-l`` or ``--local`` makes the variables local. +- ``-f`` or ``--function`` scopes the variable to the currently executing function. It is erased when the function ends. + +- ``-l`` or ``--local`` scopes the variable to the currently executing block. It is erased when the block ends. Outside of a block, this is the same as ``--function``. - ``-n NCHARS`` or ``--nchars=NCHARS`` makes ``read`` return after reading NCHARS characters or the end of the line, whichever comes first. diff --git a/src/builtin_read.cpp b/src/builtin_read.cpp index 5c2d34dea..c51f50d30 100644 --- a/src/builtin_read.cpp +++ b/src/builtin_read.cpp @@ -57,11 +57,12 @@ struct read_cmd_opts_t { bool one_line = false; }; -static const wchar_t *const short_options = L":ac:d:ghiLln:p:sStuxzP:UR:L"; +static const wchar_t *const short_options = L":ac:d:fghiLln:p:sStuxzP:UR:L"; static const struct woption long_options[] = {{L"array", no_argument, nullptr, 'a'}, {L"command", required_argument, nullptr, 'c'}, {L"delimiter", required_argument, nullptr, 'd'}, {L"export", no_argument, nullptr, 'x'}, + {L"function", no_argument, nullptr, 'f'}, {L"global", no_argument, nullptr, 'g'}, {L"help", no_argument, nullptr, 'h'}, {L"line", no_argument, nullptr, 'L'}, @@ -105,6 +106,10 @@ static int parse_cmd_opts(read_cmd_opts_t &opts, int *optind, //!OCLINT(high nc cmd); return STATUS_INVALID_ARGS; } + case L'f': { + opts.place |= ENV_FUNCTION; + break; + } case L'g': { opts.place |= ENV_GLOBAL; break; @@ -385,7 +390,7 @@ static int validate_read_args(const wchar_t *cmd, read_cmd_opts_t &opts, int arg return STATUS_INVALID_ARGS; } - if ((opts.place & ENV_LOCAL ? 1 : 0) + (opts.place & ENV_GLOBAL ? 1 : 0) + + if ((opts.place & ENV_LOCAL ? 1 : 0) + (opts.place & ENV_FUNCTION ? 1 : 0) + (opts.place & ENV_GLOBAL ? 1 : 0) + (opts.place & ENV_UNIVERSAL ? 1 : 0) > 1) { streams.err.append_format(BUILTIN_ERR_GLOCAL, cmd); diff --git a/tests/checks/read.fish b/tests/checks/read.fish index c3245d931..390b155e3 100644 --- a/tests/checks/read.fish +++ b/tests/checks/read.fish @@ -345,3 +345,22 @@ echo c $c # CHECK: a 'afoo barb' # CHECK: b # CHECK: c + +function function-scoped-read + echo foo | read --function skamtebord + set -S skamtebord + begin + echo bar | read skamtebord + echo baz | read -f craaab + end + set -S skamtebord + set -S craaab +end + +function-scoped-read +# CHECK: $skamtebord: set in local scope, unexported, with 1 elements +# CHECK: $skamtebord[1]: |foo| +# CHECK: $skamtebord: set in local scope, unexported, with 1 elements +# CHECK: $skamtebord[1]: |bar| +# CHECK: $craaab: set in local scope, unexported, with 1 elements +# CHECK: $craaab[1]: |baz|