diff options
| author | Denys Vlasenko <dvlasenk@redhat.com> | 2010-09-06 10:26:37 +0200 |
|---|---|---|
| committer | Denys Vlasenko <dvlasenk@redhat.com> | 2010-09-06 10:26:37 +0200 |
| commit | c49d2d97939d77be3d1f3bbbbf9db30a55771c15 (patch) | |
| tree | 8cf0a9ad8fd7e0d9762684fef0a7a5a4f7d43859 /shell | |
| parent | d383b49aefecea99e5bfb2f9eb2956f1c6c013e1 (diff) | |
| download | busybox-w32-c49d2d97939d77be3d1f3bbbbf9db30a55771c15.tar.gz busybox-w32-c49d2d97939d77be3d1f3bbbbf9db30a55771c15.tar.bz2 busybox-w32-c49d2d97939d77be3d1f3bbbbf9db30a55771c15.zip | |
hush: fix globbing+backslashes in unquoted $var expansion
Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
Diffstat (limited to 'shell')
| -rw-r--r-- | shell/hush.c | 134 | ||||
| -rw-r--r-- | shell/hush_test/hush-glob/glob2.right | 18 | ||||
| -rwxr-xr-x | shell/hush_test/hush-glob/glob2.tests | 27 | ||||
| -rw-r--r-- | shell/hush_test/hush-vars/var_bash4.right | 25 | ||||
| -rwxr-xr-x | shell/hush_test/hush-vars/var_bash4.tests | 52 |
5 files changed, 170 insertions, 86 deletions
diff --git a/shell/hush.c b/shell/hush.c index 2a4e80b6e..ef46372de 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
| @@ -2007,12 +2007,17 @@ static void o_addstr_with_NUL(o_string *o, const char *str) | |||
| 2007 | static void o_addblock_duplicate_backslash(o_string *o, const char *str, int len) | 2007 | static void o_addblock_duplicate_backslash(o_string *o, const char *str, int len) |
| 2008 | { | 2008 | { |
| 2009 | while (len) { | 2009 | while (len) { |
| 2010 | len--; | ||
| 2010 | o_addchr(o, *str); | 2011 | o_addchr(o, *str); |
| 2011 | if (*str == '\\') { | 2012 | if (*str++ == '\\') { |
| 2013 | /* \z -> \\\z; \<eol> -> \\<eol> */ | ||
| 2012 | o_addchr(o, '\\'); | 2014 | o_addchr(o, '\\'); |
| 2015 | if (len) { | ||
| 2016 | len--; | ||
| 2017 | o_addchr(o, '\\'); | ||
| 2018 | o_addchr(o, *str++); | ||
| 2019 | } | ||
| 2013 | } | 2020 | } |
| 2014 | str++; | ||
| 2015 | len--; | ||
| 2016 | } | 2021 | } |
| 2017 | } | 2022 | } |
| 2018 | 2023 | ||
| @@ -2067,12 +2072,8 @@ static void o_addQchr(o_string *o, int ch) | |||
| 2067 | o->data[o->length] = '\0'; | 2072 | o->data[o->length] = '\0'; |
| 2068 | } | 2073 | } |
| 2069 | 2074 | ||
| 2070 | static void o_addQblock(o_string *o, const char *str, int len) | 2075 | static void o_addqblock(o_string *o, const char *str, int len) |
| 2071 | { | 2076 | { |
| 2072 | if (!o->o_escape) { | ||
| 2073 | o_addblock(o, str, len); | ||
| 2074 | return; | ||
| 2075 | } | ||
| 2076 | while (len) { | 2077 | while (len) { |
| 2077 | char ch; | 2078 | char ch; |
| 2078 | int sz; | 2079 | int sz; |
| @@ -2099,6 +2100,15 @@ static void o_addQblock(o_string *o, const char *str, int len) | |||
| 2099 | } | 2100 | } |
| 2100 | } | 2101 | } |
| 2101 | 2102 | ||
| 2103 | static void o_addQblock(o_string *o, const char *str, int len) | ||
| 2104 | { | ||
| 2105 | if (!o->o_escape) { | ||
| 2106 | o_addblock(o, str, len); | ||
| 2107 | return; | ||
| 2108 | } | ||
| 2109 | o_addqblock(o, str, len); | ||
| 2110 | } | ||
| 2111 | |||
| 2102 | static void o_addQstr(o_string *o, const char *str) | 2112 | static void o_addQstr(o_string *o, const char *str) |
| 2103 | { | 2113 | { |
| 2104 | o_addQblock(o, str, strlen(str)); | 2114 | o_addQblock(o, str, strlen(str)); |
| @@ -2356,11 +2366,11 @@ static int glob_brace(char *pattern, o_string *o, int n) | |||
| 2356 | /* Performs globbing on last list[], | 2366 | /* Performs globbing on last list[], |
| 2357 | * saving each result as a new list[]. | 2367 | * saving each result as a new list[]. |
| 2358 | */ | 2368 | */ |
| 2359 | static int o_glob(o_string *o, int n) | 2369 | static int perform_glob(o_string *o, int n) |
| 2360 | { | 2370 | { |
| 2361 | char *pattern, *copy; | 2371 | char *pattern, *copy; |
| 2362 | 2372 | ||
| 2363 | debug_printf_glob("start o_glob: n:%d o->data:%p\n", n, o->data); | 2373 | debug_printf_glob("start perform_glob: n:%d o->data:%p\n", n, o->data); |
| 2364 | if (!o->data) | 2374 | if (!o->data) |
| 2365 | return o_save_ptr_helper(o, n); | 2375 | return o_save_ptr_helper(o, n); |
| 2366 | pattern = o->data + o_get_last_ptr(o, n); | 2376 | pattern = o->data + o_get_last_ptr(o, n); |
| @@ -2378,7 +2388,7 @@ static int o_glob(o_string *o, int n) | |||
| 2378 | n = glob_brace(copy, o, n); | 2388 | n = glob_brace(copy, o, n); |
| 2379 | free(copy); | 2389 | free(copy); |
| 2380 | if (DEBUG_GLOB) | 2390 | if (DEBUG_GLOB) |
| 2381 | debug_print_list("o_glob returning", o, n); | 2391 | debug_print_list("perform_glob returning", o, n); |
| 2382 | return n; | 2392 | return n; |
| 2383 | } | 2393 | } |
| 2384 | 2394 | ||
| @@ -2403,13 +2413,13 @@ static int glob_needed(const char *s) | |||
| 2403 | /* Performs globbing on last list[], | 2413 | /* Performs globbing on last list[], |
| 2404 | * saving each result as a new list[]. | 2414 | * saving each result as a new list[]. |
| 2405 | */ | 2415 | */ |
| 2406 | static int o_glob(o_string *o, int n) | 2416 | static int perform_glob(o_string *o, int n) |
| 2407 | { | 2417 | { |
| 2408 | glob_t globdata; | 2418 | glob_t globdata; |
| 2409 | int gr; | 2419 | int gr; |
| 2410 | char *pattern; | 2420 | char *pattern; |
| 2411 | 2421 | ||
| 2412 | debug_printf_glob("start o_glob: n:%d o->data:%p\n", n, o->data); | 2422 | debug_printf_glob("start perform_glob: n:%d o->data:%p\n", n, o->data); |
| 2413 | if (!o->data) | 2423 | if (!o->data) |
| 2414 | return o_save_ptr_helper(o, n); | 2424 | return o_save_ptr_helper(o, n); |
| 2415 | pattern = o->data + o_get_last_ptr(o, n); | 2425 | pattern = o->data + o_get_last_ptr(o, n); |
| @@ -2455,7 +2465,7 @@ static int o_glob(o_string *o, int n) | |||
| 2455 | } | 2465 | } |
| 2456 | globfree(&globdata); | 2466 | globfree(&globdata); |
| 2457 | if (DEBUG_GLOB) | 2467 | if (DEBUG_GLOB) |
| 2458 | debug_print_list("o_glob returning", o, n); | 2468 | debug_print_list("perform_glob returning", o, n); |
| 2459 | return n; | 2469 | return n; |
| 2460 | } | 2470 | } |
| 2461 | 2471 | ||
| @@ -2470,7 +2480,7 @@ static int o_save_ptr(o_string *o, int n) | |||
| 2470 | * (if it was requested back then when it was filled) | 2480 | * (if it was requested back then when it was filled) |
| 2471 | * so don't do that again! */ | 2481 | * so don't do that again! */ |
| 2472 | if (!o->has_empty_slot) | 2482 | if (!o->has_empty_slot) |
| 2473 | return o_glob(o, n); /* o_save_ptr_helper is inside */ | 2483 | return perform_glob(o, n); /* o_save_ptr_helper is inside */ |
| 2474 | } | 2484 | } |
| 2475 | return o_save_ptr_helper(o, n); | 2485 | return o_save_ptr_helper(o, n); |
| 2476 | } | 2486 | } |
| @@ -2927,15 +2937,6 @@ static int done_word(o_string *word, struct parse_context *ctx) | |||
| 2927 | (ctx->ctx_res_w == RES_SNTX)); | 2937 | (ctx->ctx_res_w == RES_SNTX)); |
| 2928 | return (ctx->ctx_res_w == RES_SNTX); | 2938 | return (ctx->ctx_res_w == RES_SNTX); |
| 2929 | } | 2939 | } |
| 2930 | # ifdef CMD_SINGLEWORD_NOGLOB_COND | ||
| 2931 | if (strcmp(word->data, "export") == 0 | ||
| 2932 | # if ENABLE_HUSH_LOCAL | ||
| 2933 | || strcmp(word->data, "local") == 0 | ||
| 2934 | # endif | ||
| 2935 | ) { | ||
| 2936 | command->cmd_type = CMD_SINGLEWORD_NOGLOB_COND; | ||
| 2937 | } else | ||
| 2938 | # endif | ||
| 2939 | # if ENABLE_HUSH_BASH_COMPAT | 2940 | # if ENABLE_HUSH_BASH_COMPAT |
| 2940 | if (strcmp(word->data, "[[") == 0) { | 2941 | if (strcmp(word->data, "[[") == 0) { |
| 2941 | command->cmd_type = CMD_SINGLEWORD_NOGLOB; | 2942 | command->cmd_type = CMD_SINGLEWORD_NOGLOB; |
| @@ -4371,10 +4372,19 @@ static int expand_on_ifs(o_string *output, int n, const char *str) | |||
| 4371 | while (1) { | 4372 | while (1) { |
| 4372 | int word_len = strcspn(str, G.ifs); | 4373 | int word_len = strcspn(str, G.ifs); |
| 4373 | if (word_len) { | 4374 | if (word_len) { |
| 4374 | if (output->o_escape || !output->o_glob) | 4375 | if (output->o_escape) |
| 4375 | o_addQblock(output, str, word_len); | 4376 | o_addqblock(output, str, word_len); |
| 4376 | else /* protect backslashes against globbing up :) */ | 4377 | else if (!output->o_glob) |
| 4378 | o_addblock(output, str, word_len); | ||
| 4379 | else /* if (!escape && glob) */ { | ||
| 4380 | /* Protect backslashes against globbing up :) | ||
| 4381 | * Example: "v='\*'; echo b$v" | ||
| 4382 | */ | ||
| 4377 | o_addblock_duplicate_backslash(output, str, word_len); | 4383 | o_addblock_duplicate_backslash(output, str, word_len); |
| 4384 | /*/ Why can't we do it easier? */ | ||
| 4385 | /*o_addblock(output, str, word_len); - WRONG: "v='\*'; echo Z$v" prints "Z*" instead of "Z\*" */ | ||
| 4386 | /*o_addqblock(output, str, word_len); - WRONG: "v='*'; echo Z$v" prints "Z*" instead of Z* files */ | ||
| 4387 | } | ||
| 4378 | str += word_len; | 4388 | str += word_len; |
| 4379 | } | 4389 | } |
| 4380 | if (!*str) /* EOL - do not finalize word */ | 4390 | if (!*str) /* EOL - do not finalize word */ |
| @@ -4594,8 +4604,9 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha | |||
| 4594 | if (exp_op == *exp_word) /* ## or %% */ | 4604 | if (exp_op == *exp_word) /* ## or %% */ |
| 4595 | exp_word++; | 4605 | exp_word++; |
| 4596 | //TODO: avoid xstrdup unless needed | 4606 | //TODO: avoid xstrdup unless needed |
| 4597 | // (see HACK ALERT below) | 4607 | // (see HACK ALERT below for an example) |
| 4598 | val = to_be_freed = xstrdup(val); | 4608 | val = to_be_freed = xstrdup(val); |
| 4609 | //TODO: fix expansion rules: | ||
| 4599 | exp_exp_word = expand_pseudo_dquoted(exp_word); | 4610 | exp_exp_word = expand_pseudo_dquoted(exp_word); |
| 4600 | if (exp_exp_word) | 4611 | if (exp_exp_word) |
| 4601 | exp_word = exp_exp_word; | 4612 | exp_word = exp_exp_word; |
| @@ -4613,10 +4624,26 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha | |||
| 4613 | } | 4624 | } |
| 4614 | #if ENABLE_HUSH_BASH_COMPAT | 4625 | #if ENABLE_HUSH_BASH_COMPAT |
| 4615 | else if (exp_op == '/' || exp_op == '\\') { | 4626 | else if (exp_op == '/' || exp_op == '\\') { |
| 4627 | /* It's ${var/[/]pattern[/repl]} thing. | ||
| 4628 | * Note that in encoded form it has TWO parts: | ||
| 4629 | * var/pattern<SPECIAL_VAR_SYMBOL>repl<SPECIAL_VAR_SYMBOL> | ||
| 4630 | */ | ||
| 4616 | /* Empty variable always gives nothing: */ | 4631 | /* Empty variable always gives nothing: */ |
| 4617 | // "v=''; echo ${v/*/w}" prints "" | 4632 | // "v=''; echo ${v/*/w}" prints "", not "w" |
| 4618 | if (val && val[0]) { | 4633 | if (val && val[0]) { |
| 4619 | /* It's ${var/[/]pattern[/repl]} thing */ | 4634 | /* It's ${var/[/]pattern[/repl]} thing */ |
| 4635 | /* | ||
| 4636 | * Pattern is taken literally, while | ||
| 4637 | * repl should be de-backslased and globbed | ||
| 4638 | * by the usual expansion rules: | ||
| 4639 | * >az; >bz; | ||
| 4640 | * v='a bz'; echo "${v/a*z/a*z}" prints "a*z" | ||
| 4641 | * v='a bz'; echo "${v/a*z/\z}" prints "\z" | ||
| 4642 | * v='a bz'; echo ${v/a*z/a*z} prints "az" | ||
| 4643 | * v='a bz'; echo ${v/a*z/\z} prints "z" | ||
| 4644 | * (note that a*z _pattern_ is never globbed!) | ||
| 4645 | */ | ||
| 4646 | //TODO: fix expansion rules: | ||
| 4620 | char *pattern, *repl, *t; | 4647 | char *pattern, *repl, *t; |
| 4621 | pattern = expand_pseudo_dquoted(exp_word); | 4648 | pattern = expand_pseudo_dquoted(exp_word); |
| 4622 | if (!pattern) | 4649 | if (!pattern) |
| @@ -4772,7 +4799,6 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg, char | |||
| 4772 | 4799 | ||
| 4773 | while ((p = strchr(arg, SPECIAL_VAR_SYMBOL)) != NULL) { | 4800 | while ((p = strchr(arg, SPECIAL_VAR_SYMBOL)) != NULL) { |
| 4774 | char first_ch; | 4801 | char first_ch; |
| 4775 | int i; | ||
| 4776 | char *to_be_freed = NULL; | 4802 | char *to_be_freed = NULL; |
| 4777 | const char *val = NULL; | 4803 | const char *val = NULL; |
| 4778 | #if ENABLE_HUSH_TICK | 4804 | #if ENABLE_HUSH_TICK |
| @@ -4795,10 +4821,11 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg, char | |||
| 4795 | switch (first_ch & 0x7f) { | 4821 | switch (first_ch & 0x7f) { |
| 4796 | /* Highest bit in first_ch indicates that var is double-quoted */ | 4822 | /* Highest bit in first_ch indicates that var is double-quoted */ |
| 4797 | case '*': | 4823 | case '*': |
| 4798 | case '@': | 4824 | case '@': { |
| 4799 | i = 1; | 4825 | int i; |
| 4800 | if (!G.global_argv[i]) | 4826 | if (!G.global_argv[1]) |
| 4801 | break; | 4827 | break; |
| 4828 | i = 1; | ||
| 4802 | ored_ch |= first_ch; /* do it for "$@" _now_, when we know it's not empty */ | 4829 | ored_ch |= first_ch; /* do it for "$@" _now_, when we know it's not empty */ |
| 4803 | if (!(first_ch & 0x80)) { /* unquoted $* or $@ */ | 4830 | if (!(first_ch & 0x80)) { /* unquoted $* or $@ */ |
| 4804 | smallint sv = output->o_escape; | 4831 | smallint sv = output->o_escape; |
| @@ -4839,6 +4866,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg, char | |||
| 4839 | } | 4866 | } |
| 4840 | } | 4867 | } |
| 4841 | break; | 4868 | break; |
| 4869 | } | ||
| 4842 | case SPECIAL_VAR_SYMBOL: /* <SPECIAL_VAR_SYMBOL><SPECIAL_VAR_SYMBOL> */ | 4870 | case SPECIAL_VAR_SYMBOL: /* <SPECIAL_VAR_SYMBOL><SPECIAL_VAR_SYMBOL> */ |
| 4843 | /* "Empty variable", used to make "" etc to not disappear */ | 4871 | /* "Empty variable", used to make "" etc to not disappear */ |
| 4844 | arg++; | 4872 | arg++; |
| @@ -4984,41 +5012,6 @@ static char **expand_strvec_to_strvec_singleword_noglob(char **argv) | |||
| 4984 | } | 5012 | } |
| 4985 | #endif | 5013 | #endif |
| 4986 | 5014 | ||
| 4987 | #ifdef CMD_SINGLEWORD_NOGLOB_COND | ||
| 4988 | static char **expand_strvec_to_strvec_singleword_noglob_cond(char **argv) | ||
| 4989 | { | ||
| 4990 | int n; | ||
| 4991 | char **list; | ||
| 4992 | char **v; | ||
| 4993 | o_string output = NULL_O_STRING; | ||
| 4994 | |||
| 4995 | n = 0; | ||
| 4996 | v = argv; | ||
| 4997 | while (*v) { | ||
| 4998 | int is_var = is_well_formed_var_name(*v, '='); | ||
| 4999 | /* is_var * 0x80: singleword expansion for vars */ | ||
| 5000 | n = expand_vars_to_list(&output, n, *v, is_var * 0x80); | ||
| 5001 | |||
| 5002 | /* Subtle! expand_vars_to_list did not glob last word yet. | ||
| 5003 | * It does this only when fed with further data. | ||
| 5004 | * Therefore we set globbing flags AFTER it, not before: | ||
| 5005 | */ | ||
| 5006 | |||
| 5007 | /* if it is not recognizably abc=...; then: */ | ||
| 5008 | output.o_escape = !is_var; /* protect against globbing for "$var" */ | ||
| 5009 | /* (unquoted $var will temporarily switch it off) */ | ||
| 5010 | output.o_glob = !is_var; /* and indeed do globbing */ | ||
| 5011 | v++; | ||
| 5012 | } | ||
| 5013 | debug_print_list("expand_cond", &output, n); | ||
| 5014 | |||
| 5015 | /* output.data (malloced in one block) gets returned in "list" */ | ||
| 5016 | list = o_finalize_list(&output, n); | ||
| 5017 | debug_print_strings("expand_cond[1]", list); | ||
| 5018 | return list; | ||
| 5019 | } | ||
| 5020 | #endif | ||
| 5021 | |||
| 5022 | /* Used for expansion of right hand of assignments */ | 5015 | /* Used for expansion of right hand of assignments */ |
| 5023 | /* NB: should NOT do globbing! | 5016 | /* NB: should NOT do globbing! |
| 5024 | * "export v=/bin/c*; env | grep ^v=" outputs "v=/bin/c*" */ | 5017 | * "export v=/bin/c*; env | grep ^v=" outputs "v=/bin/c*" */ |
| @@ -6567,11 +6560,6 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
| 6567 | argv_expanded = expand_strvec_to_strvec_singleword_noglob(argv + command->assignment_cnt); | 6560 | argv_expanded = expand_strvec_to_strvec_singleword_noglob(argv + command->assignment_cnt); |
| 6568 | } | 6561 | } |
| 6569 | #endif | 6562 | #endif |
| 6570 | #ifdef CMD_SINGLEWORD_NOGLOB_COND | ||
| 6571 | else if (command->cmd_type == CMD_SINGLEWORD_NOGLOB_COND) { | ||
| 6572 | argv_expanded = expand_strvec_to_strvec_singleword_noglob_cond(argv + command->assignment_cnt); | ||
| 6573 | } | ||
| 6574 | #endif | ||
| 6575 | else { | 6563 | else { |
| 6576 | argv_expanded = expand_strvec_to_strvec(argv + command->assignment_cnt); | 6564 | argv_expanded = expand_strvec_to_strvec(argv + command->assignment_cnt); |
| 6577 | } | 6565 | } |
diff --git a/shell/hush_test/hush-glob/glob2.right b/shell/hush_test/hush-glob/glob2.right new file mode 100644 index 000000000..7a70c2263 --- /dev/null +++ b/shell/hush_test/hush-glob/glob2.right | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | Expected Actual | ||
| 2 | Z\* : Z\* | ||
| 3 | Z* : Z* | ||
| 4 | Z\f : Z\f | ||
| 5 | Z\* : Z\* | ||
| 6 | |||
| 7 | Z\z : Z\z | ||
| 8 | Zz : Zz | ||
| 9 | Z\z : Z\z | ||
| 10 | Z\z : Z\z | ||
| 11 | |||
| 12 | Z\ : Z\ | ||
| 13 | Z\ : Z\ | ||
| 14 | |||
| 15 | Z\f Zf : Z\f Zf | ||
| 16 | Z\f Zf : Z\f Zf | ||
| 17 | |||
| 18 | Done: 0 | ||
diff --git a/shell/hush_test/hush-glob/glob2.tests b/shell/hush_test/hush-glob/glob2.tests new file mode 100755 index 000000000..4dbc92599 --- /dev/null +++ b/shell/hush_test/hush-glob/glob2.tests | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | # This test demonstrates that in unquoted $v, backslashes expand by this rule: | ||
| 2 | # \z -> \\\z; \<eol> -> \\<eol> (for any z, special or not), | ||
| 3 | # and subsequently globbing converts \\ to \ and treats \z as literal z | ||
| 4 | # even if it is a special char. | ||
| 5 | |||
| 6 | >'Zf' | ||
| 7 | >'Z\f' | ||
| 8 | echo 'Expected' 'Actual' | ||
| 9 | v='\*'; echo 'Z\* :' Z$v | ||
| 10 | echo 'Z* :' Z\* | ||
| 11 | echo 'Z\f :' Z\\* | ||
| 12 | echo 'Z\* :' Z\\\* # NB! only this matches Z$v output | ||
| 13 | echo | ||
| 14 | v='\z'; echo 'Z\z :' Z$v | ||
| 15 | echo 'Zz :' Z\z | ||
| 16 | echo 'Z\z :' Z\\z | ||
| 17 | echo 'Z\z :' Z\\\z | ||
| 18 | echo | ||
| 19 | v='\'; echo 'Z\ :' Z$v | ||
| 20 | echo 'Z\ :' Z\\ | ||
| 21 | echo | ||
| 22 | v='*'; echo 'Z\f Zf :' Z$v | ||
| 23 | echo 'Z\f Zf :' Z* | ||
| 24 | echo | ||
| 25 | |||
| 26 | rm 'Z\f' 'Zf' | ||
| 27 | echo Done: $? | ||
diff --git a/shell/hush_test/hush-vars/var_bash4.right b/shell/hush_test/hush-vars/var_bash4.right index 600e8532f..0ef1bf661 100644 --- a/shell/hush_test/hush-vars/var_bash4.right +++ b/shell/hush_test/hush-vars/var_bash4.right | |||
| @@ -1,23 +1,40 @@ | |||
| 1 | Source: a*b\*c | 1 | Source: a*b\*c |
| 2 | Replace str: _\\_\z_ | 2 | Replace str: _\\_\z_ |
| 3 | Pattern: single backslash and star: "replace literal star" | 3 | Pattern: single backslash and star: "replace literal star" |
| 4 | In assignment: a_\_z_b\*c | ||
| 5 | Unquoted: a_\_z_b\*c | 4 | Unquoted: a_\_z_b\*c |
| 5 | Unquoted =: a_\_z_b\*c | ||
| 6 | Quoted: a_\_\z_b\*c | 6 | Quoted: a_\_\z_b\*c |
| 7 | Quoted =: a_\_\z_b\*c | ||
| 7 | Pattern: double backslash and star: "replace backslash and everything after it" | 8 | Pattern: double backslash and star: "replace backslash and everything after it" |
| 8 | In assignment: a*b_\_z_ | ||
| 9 | Unquoted: a*b_\_z_ | 9 | Unquoted: a*b_\_z_ |
| 10 | Unquoted =: a*b_\_z_ | ||
| 10 | Quoted: a*b_\_\z_ | 11 | Quoted: a*b_\_\z_ |
| 12 | Quoted =: a*b_\_\z_ | ||
| 11 | 13 | ||
| 12 | Source: a\bc | 14 | Source: a\bc |
| 13 | Replace str: _\\_\z_ | 15 | Replace str: _\\_\z_ |
| 14 | Pattern: single backslash and b: "replace b" | 16 | Pattern: single backslash and b: "replace b" |
| 15 | In assignment: a\_\_z_c | ||
| 16 | Unquoted: a\_\_z_c | 17 | Unquoted: a\_\_z_c |
| 18 | Unquoted =: a\_\_z_c | ||
| 17 | Quoted: a\_\_\z_c | 19 | Quoted: a\_\_\z_c |
| 20 | Quoted =: a\_\_\z_c | ||
| 18 | Pattern: double backslash and b: "replace backslash and b" | 21 | Pattern: double backslash and b: "replace backslash and b" |
| 19 | In assignment: a_\_z_c | ||
| 20 | Unquoted: a_\_z_c | 22 | Unquoted: a_\_z_c |
| 23 | Unquoted =: a_\_z_c | ||
| 21 | Quoted: a_\_\z_c | 24 | Quoted: a_\_\z_c |
| 25 | Quoted =: a_\_\z_c | ||
| 26 | |||
| 27 | Source: a\bc | ||
| 28 | Replace str: _\\_\z_ (as variable $s) | ||
| 29 | Pattern: single backslash and b: "replace b" | ||
| 30 | Unquoted: a\_\\_\z_c | ||
| 31 | Unquoted =: a\_\\_\z_c | ||
| 32 | Quoted: a\_\\_\z_c | ||
| 33 | Quoted =: a\_\\_\z_c | ||
| 34 | Pattern: double backslash and b: "replace backslash and b" | ||
| 35 | Unquoted: a_\\_\z_c | ||
| 36 | Unquoted =: a_\\_\z_c | ||
| 37 | Quoted: a_\\_\z_c | ||
| 38 | Quoted =: a_\\_\z_c | ||
| 22 | 39 | ||
| 23 | Done: 0 | 40 | Done: 0 |
diff --git a/shell/hush_test/hush-vars/var_bash4.tests b/shell/hush_test/hush-vars/var_bash4.tests index d5470614b..32aa2b34c 100755 --- a/shell/hush_test/hush-vars/var_bash4.tests +++ b/shell/hush_test/hush-vars/var_bash4.tests | |||
| @@ -6,23 +6,30 @@ | |||
| 6 | # even in quotes. | 6 | # even in quotes. |
| 7 | # | 7 | # |
| 8 | # bash4 (and probably bash3 too): "Quoted:" results are different from | 8 | # bash4 (and probably bash3 too): "Quoted:" results are different from |
| 9 | # unquoted and assignment expansions - they have a backslash before z. | 9 | # unquoted expansions - they have a backslash before z. |
| 10 | # | ||
| 11 | # The difference only exists if repl is a literal. If it is a variable: | ||
| 12 | # ${v/.../$s}, then all backslashes are preserved in both cases. | ||
| 10 | 13 | ||
| 11 | v='a*b\*c' | 14 | v='a*b\*c' |
| 12 | echo 'Source: ' "$v" | 15 | echo 'Source: ' "$v" |
| 13 | echo 'Replace str: ' '_\\_\z_' | 16 | echo 'Replace str: ' '_\\_\z_' |
| 14 | 17 | ||
| 15 | echo 'Pattern: ' 'single backslash and star: "replace literal star"' | 18 | echo 'Pattern: ' 'single backslash and star: "replace literal star"' |
| 16 | r=${v/\*/_\\_\z_} | ||
| 17 | echo 'In assignment:' "$r" | ||
| 18 | echo 'Unquoted: ' ${v/\*/_\\_\z_} | 19 | echo 'Unquoted: ' ${v/\*/_\\_\z_} |
| 20 | r=${v/\*/_\\_\z_} | ||
| 21 | echo 'Unquoted =: ' "$r" | ||
| 19 | echo 'Quoted: ' "${v/\*/_\\_\z_}" | 22 | echo 'Quoted: ' "${v/\*/_\\_\z_}" |
| 23 | r="${v/\*/_\\_\z_}" | ||
| 24 | echo 'Quoted =: ' "$r" | ||
| 20 | 25 | ||
| 21 | echo 'Pattern: ' 'double backslash and star: "replace backslash and everything after it"' | 26 | echo 'Pattern: ' 'double backslash and star: "replace backslash and everything after it"' |
| 22 | r=${v/\\*/_\\_\z_} | ||
| 23 | echo 'In assignment:' "$r" | ||
| 24 | echo 'Unquoted: ' ${v/\\*/_\\_\z_} | 27 | echo 'Unquoted: ' ${v/\\*/_\\_\z_} |
| 28 | r=${v/\\*/_\\_\z_} | ||
| 29 | echo 'Unquoted =: ' "$r" | ||
| 25 | echo 'Quoted: ' "${v/\\*/_\\_\z_}" | 30 | echo 'Quoted: ' "${v/\\*/_\\_\z_}" |
| 31 | r="${v/\\*/_\\_\z_}" | ||
| 32 | echo 'Quoted =: ' "$r" | ||
| 26 | 33 | ||
| 27 | echo | 34 | echo |
| 28 | 35 | ||
| @@ -31,16 +38,43 @@ echo 'Source: ' "$v" | |||
| 31 | echo 'Replace str: ' '_\\_\z_' | 38 | echo 'Replace str: ' '_\\_\z_' |
| 32 | 39 | ||
| 33 | echo 'Pattern: ' 'single backslash and b: "replace b"' | 40 | echo 'Pattern: ' 'single backslash and b: "replace b"' |
| 34 | r=${v/\b/_\\_\z_} | ||
| 35 | echo 'In assignment:' "$r" | ||
| 36 | echo 'Unquoted: ' ${v/\b/_\\_\z_} | 41 | echo 'Unquoted: ' ${v/\b/_\\_\z_} |
| 42 | r=${v/\b/_\\_\z_} | ||
| 43 | echo 'Unquoted =: ' "$r" | ||
| 37 | echo 'Quoted: ' "${v/\b/_\\_\z_}" | 44 | echo 'Quoted: ' "${v/\b/_\\_\z_}" |
| 45 | r="${v/\b/_\\_\z_}" | ||
| 46 | echo 'Quoted =: ' "$r" | ||
| 38 | 47 | ||
| 39 | echo 'Pattern: ' 'double backslash and b: "replace backslash and b"' | 48 | echo 'Pattern: ' 'double backslash and b: "replace backslash and b"' |
| 40 | r=${v/\\b/_\\_\z_} | ||
| 41 | echo 'In assignment:' "$r" | ||
| 42 | echo 'Unquoted: ' ${v/\\b/_\\_\z_} | 49 | echo 'Unquoted: ' ${v/\\b/_\\_\z_} |
| 50 | r=${v/\\b/_\\_\z_} | ||
| 51 | echo 'Unquoted =: ' "$r" | ||
| 43 | echo 'Quoted: ' "${v/\\b/_\\_\z_}" | 52 | echo 'Quoted: ' "${v/\\b/_\\_\z_}" |
| 53 | r="${v/\\b/_\\_\z_}" | ||
| 54 | echo 'Quoted =: ' "$r" | ||
| 55 | |||
| 56 | echo | ||
| 57 | |||
| 58 | v='a\bc' | ||
| 59 | s='_\\_\z_' | ||
| 60 | echo 'Source: ' "$v" | ||
| 61 | echo 'Replace str: ' "$s" '(as variable $s)' | ||
| 62 | |||
| 63 | echo 'Pattern: ' 'single backslash and b: "replace b"' | ||
| 64 | echo 'Unquoted: ' ${v/\b/$s} | ||
| 65 | r=${v/\b/$s} | ||
| 66 | echo 'Unquoted =: ' "$r" | ||
| 67 | echo 'Quoted: ' "${v/\b/$s}" | ||
| 68 | r="${v/\b/$s}" | ||
| 69 | echo 'Quoted =: ' "$r" | ||
| 70 | |||
| 71 | echo 'Pattern: ' 'double backslash and b: "replace backslash and b"' | ||
| 72 | echo 'Unquoted: ' ${v/\\b/$s} | ||
| 73 | r=${v/\\b/$s} | ||
| 74 | echo 'Unquoted =: ' "$r" | ||
| 75 | echo 'Quoted: ' "${v/\\b/$s}" | ||
| 76 | r="${v/\\b/$s}" | ||
| 77 | echo 'Quoted =: ' "$r" | ||
| 44 | 78 | ||
| 45 | echo | 79 | echo |
| 46 | 80 | ||
