summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <dvlasenk@redhat.com>2010-09-06 10:26:37 +0200
committerDenys Vlasenko <dvlasenk@redhat.com>2010-09-06 10:26:37 +0200
commitc49d2d97939d77be3d1f3bbbbf9db30a55771c15 (patch)
tree8cf0a9ad8fd7e0d9762684fef0a7a5a4f7d43859
parentd383b49aefecea99e5bfb2f9eb2956f1c6c013e1 (diff)
downloadbusybox-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>
-rw-r--r--shell/hush.c134
-rw-r--r--shell/hush_test/hush-glob/glob2.right18
-rwxr-xr-xshell/hush_test/hush-glob/glob2.tests27
-rw-r--r--shell/hush_test/hush-vars/var_bash4.right25
-rwxr-xr-xshell/hush_test/hush-vars/var_bash4.tests52
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)
2007static void o_addblock_duplicate_backslash(o_string *o, const char *str, int len) 2007static 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
2070static void o_addQblock(o_string *o, const char *str, int len) 2075static 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
2103static 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
2102static void o_addQstr(o_string *o, const char *str) 2112static 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 */
2359static int o_glob(o_string *o, int n) 2369static 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 */
2406static int o_glob(o_string *o, int n) 2416static 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
4988static 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 @@
1Expected Actual
2Z\* : Z\*
3Z* : Z*
4Z\f : Z\f
5Z\* : Z\*
6
7Z\z : Z\z
8Zz : Zz
9Z\z : Z\z
10Z\z : Z\z
11
12Z\ : Z\
13Z\ : Z\
14
15Z\f Zf : Z\f Zf
16Z\f Zf : Z\f Zf
17
18Done: 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'
9v='\*'; echo 'Z\* :' Z$v
10 echo 'Z* :' Z\*
11 echo 'Z\f :' Z\\*
12 echo 'Z\* :' Z\\\* # NB! only this matches Z$v output
13echo
14v='\z'; echo 'Z\z :' Z$v
15 echo 'Zz :' Z\z
16 echo 'Z\z :' Z\\z
17 echo 'Z\z :' Z\\\z
18echo
19v='\'; echo 'Z\ :' Z$v
20 echo 'Z\ :' Z\\
21echo
22v='*'; echo 'Z\f Zf :' Z$v
23 echo 'Z\f Zf :' Z*
24echo
25
26rm 'Z\f' 'Zf'
27echo 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 @@
1Source: a*b\*c 1Source: a*b\*c
2Replace str: _\\_\z_ 2Replace str: _\\_\z_
3Pattern: single backslash and star: "replace literal star" 3Pattern: single backslash and star: "replace literal star"
4In assignment: a_\_z_b\*c
5Unquoted: a_\_z_b\*c 4Unquoted: a_\_z_b\*c
5Unquoted =: a_\_z_b\*c
6Quoted: a_\_\z_b\*c 6Quoted: a_\_\z_b\*c
7Quoted =: a_\_\z_b\*c
7Pattern: double backslash and star: "replace backslash and everything after it" 8Pattern: double backslash and star: "replace backslash and everything after it"
8In assignment: a*b_\_z_
9Unquoted: a*b_\_z_ 9Unquoted: a*b_\_z_
10Unquoted =: a*b_\_z_
10Quoted: a*b_\_\z_ 11Quoted: a*b_\_\z_
12Quoted =: a*b_\_\z_
11 13
12Source: a\bc 14Source: a\bc
13Replace str: _\\_\z_ 15Replace str: _\\_\z_
14Pattern: single backslash and b: "replace b" 16Pattern: single backslash and b: "replace b"
15In assignment: a\_\_z_c
16Unquoted: a\_\_z_c 17Unquoted: a\_\_z_c
18Unquoted =: a\_\_z_c
17Quoted: a\_\_\z_c 19Quoted: a\_\_\z_c
20Quoted =: a\_\_\z_c
18Pattern: double backslash and b: "replace backslash and b" 21Pattern: double backslash and b: "replace backslash and b"
19In assignment: a_\_z_c
20Unquoted: a_\_z_c 22Unquoted: a_\_z_c
23Unquoted =: a_\_z_c
21Quoted: a_\_\z_c 24Quoted: a_\_\z_c
25Quoted =: a_\_\z_c
26
27Source: a\bc
28Replace str: _\\_\z_ (as variable $s)
29Pattern: single backslash and b: "replace b"
30Unquoted: a\_\\_\z_c
31Unquoted =: a\_\\_\z_c
32Quoted: a\_\\_\z_c
33Quoted =: a\_\\_\z_c
34Pattern: double backslash and b: "replace backslash and b"
35Unquoted: a_\\_\z_c
36Unquoted =: a_\\_\z_c
37Quoted: a_\\_\z_c
38Quoted =: a_\\_\z_c
22 39
23Done: 0 40Done: 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
11v='a*b\*c' 14v='a*b\*c'
12echo 'Source: ' "$v" 15echo 'Source: ' "$v"
13echo 'Replace str: ' '_\\_\z_' 16echo 'Replace str: ' '_\\_\z_'
14 17
15echo 'Pattern: ' 'single backslash and star: "replace literal star"' 18echo 'Pattern: ' 'single backslash and star: "replace literal star"'
16r=${v/\*/_\\_\z_}
17echo 'In assignment:' "$r"
18echo 'Unquoted: ' ${v/\*/_\\_\z_} 19echo 'Unquoted: ' ${v/\*/_\\_\z_}
20r=${v/\*/_\\_\z_}
21echo 'Unquoted =: ' "$r"
19echo 'Quoted: ' "${v/\*/_\\_\z_}" 22echo 'Quoted: ' "${v/\*/_\\_\z_}"
23r="${v/\*/_\\_\z_}"
24echo 'Quoted =: ' "$r"
20 25
21echo 'Pattern: ' 'double backslash and star: "replace backslash and everything after it"' 26echo 'Pattern: ' 'double backslash and star: "replace backslash and everything after it"'
22r=${v/\\*/_\\_\z_}
23echo 'In assignment:' "$r"
24echo 'Unquoted: ' ${v/\\*/_\\_\z_} 27echo 'Unquoted: ' ${v/\\*/_\\_\z_}
28r=${v/\\*/_\\_\z_}
29echo 'Unquoted =: ' "$r"
25echo 'Quoted: ' "${v/\\*/_\\_\z_}" 30echo 'Quoted: ' "${v/\\*/_\\_\z_}"
31r="${v/\\*/_\\_\z_}"
32echo 'Quoted =: ' "$r"
26 33
27echo 34echo
28 35
@@ -31,16 +38,43 @@ echo 'Source: ' "$v"
31echo 'Replace str: ' '_\\_\z_' 38echo 'Replace str: ' '_\\_\z_'
32 39
33echo 'Pattern: ' 'single backslash and b: "replace b"' 40echo 'Pattern: ' 'single backslash and b: "replace b"'
34r=${v/\b/_\\_\z_}
35echo 'In assignment:' "$r"
36echo 'Unquoted: ' ${v/\b/_\\_\z_} 41echo 'Unquoted: ' ${v/\b/_\\_\z_}
42r=${v/\b/_\\_\z_}
43echo 'Unquoted =: ' "$r"
37echo 'Quoted: ' "${v/\b/_\\_\z_}" 44echo 'Quoted: ' "${v/\b/_\\_\z_}"
45r="${v/\b/_\\_\z_}"
46echo 'Quoted =: ' "$r"
38 47
39echo 'Pattern: ' 'double backslash and b: "replace backslash and b"' 48echo 'Pattern: ' 'double backslash and b: "replace backslash and b"'
40r=${v/\\b/_\\_\z_}
41echo 'In assignment:' "$r"
42echo 'Unquoted: ' ${v/\\b/_\\_\z_} 49echo 'Unquoted: ' ${v/\\b/_\\_\z_}
50r=${v/\\b/_\\_\z_}
51echo 'Unquoted =: ' "$r"
43echo 'Quoted: ' "${v/\\b/_\\_\z_}" 52echo 'Quoted: ' "${v/\\b/_\\_\z_}"
53r="${v/\\b/_\\_\z_}"
54echo 'Quoted =: ' "$r"
55
56echo
57
58v='a\bc'
59s='_\\_\z_'
60echo 'Source: ' "$v"
61echo 'Replace str: ' "$s" '(as variable $s)'
62
63echo 'Pattern: ' 'single backslash and b: "replace b"'
64echo 'Unquoted: ' ${v/\b/$s}
65r=${v/\b/$s}
66echo 'Unquoted =: ' "$r"
67echo 'Quoted: ' "${v/\b/$s}"
68r="${v/\b/$s}"
69echo 'Quoted =: ' "$r"
70
71echo 'Pattern: ' 'double backslash and b: "replace backslash and b"'
72echo 'Unquoted: ' ${v/\\b/$s}
73r=${v/\\b/$s}
74echo 'Unquoted =: ' "$r"
75echo 'Quoted: ' "${v/\\b/$s}"
76r="${v/\\b/$s}"
77echo 'Quoted =: ' "$r"
44 78
45echo 79echo
46 80