string match: Only import variables for the first matching argument

This makes it work the same whether it quits early (with "-q") or not,
and it's generally nice to nail this down.

See #7495.
This commit is contained in:
Fabian Homborg 2020-12-04 18:45:08 +01:00
parent f6da895df4
commit 02efce51a9
2 changed files with 25 additions and 2 deletions

View File

@ -833,6 +833,7 @@ class pcre2_matcher_t : public string_matcher_t {
const wchar_t *argv0;
compiled_regex_t regex;
parser_t &parser;
bool imported_vars = false;
enum class match_result_t {
pcre2_error = -1,
@ -1058,7 +1059,12 @@ class pcre2_matcher_t : public string_matcher_t {
PCRE2_SIZE arglen = arg.length();
auto rc = report_match(arg, pcre2_match(regex.code, PCRE2_SPTR(arg.c_str()), arglen, 0, 0,
regex.match, nullptr));
var_importer.import_vars(rc == match_result_t::match);
// We only import variables for the *first matching argument*
bool had_match = false;
if (rc == match_result_t::match && !imported_vars) {
var_importer.import_vars(rc == match_result_t::match);
had_match = true;
}
switch (rc) {
case match_result_t::pcre2_error:
@ -1100,6 +1106,7 @@ class pcre2_matcher_t : public string_matcher_t {
}
}
imported_vars |= had_match;
return true;
}
};

View File

@ -13,7 +13,7 @@ printf "%s\n" $words
# CHECK: world
# Capture multiple variables
echo "hello world" | string match -rq -- '^(?<word1>[^ ]+) (?<word2>.*)$'
echo "hello world"\n"snello snorld" | string match -rq -- '^(?<word1>[^ ]+) (?<word2>.*)$'
printf "%s\n" $word1 $word2
# CHECK: hello
# CHECK: world
@ -35,6 +35,22 @@ printf "%s\n" $punctuation
# CHECK: ,
# CHECK: !
# Same thing with multiple arguments
set word
set punctuation
printf '%s\n' "hello world, boy!" "shello shorld, shoy!" | string match -a -qr -- '(?<word>[^ .,!;]+)(?<punctuation>[.,!;])?'
echo $word
# CHECK: hello world boy
printf "%s\n" $punctuation
# CHECK:
# CHECK: ,
# CHECK: !
# Verify read-only variables may not be imported
echo hello | string match -rq "(?<version>.*)"
# CHECKERR: Modification of read-only variable "version" is not allowed
# Verify that the *first matching argument* is used.
string match -rq '(?<bee>b.*)' -- aaa ba ccc be
echo $bee
# CHECK: ba