Failing shell code under busybox 1.36.1 that worked with 1.31.1
'David Leonard'
d+busybox at adaptive-enterprises.com
Fri Feb 16 03:33:46 UTC 2024
Well, I also tried adding support for bash's ${var at Q} (which I think is the
most readable way to solve quoting) but it seems I really don't understand
how ash's subevalvar() works after all :)
./busybox ash -xvc 'v="ab cd"; echo "(${v at Q})"'
+ v='ab cd'
ash: vstransform:str='Q'
ash: vstransform:startp='ab cd'
+ echo ''"'"'a'"'"'ab cd'"'"')'
'a'ab cd')
diff --git a/shell/ash.c b/shell/ash.c
index ae1b79f37..8d5d6146d 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -222,6 +222,8 @@
#define IF_BASH_PATTERN_SUBST IF_ASH_BASH_COMPAT
#define BASH_SUBSTR ENABLE_ASH_BASH_COMPAT
#define IF_BASH_SUBSTR IF_ASH_BASH_COMPAT
+#define BASH_PARAM_TRANSFORM ENABLE_ASH_BASH_COMPAT
+#define IF_BASH_PARAM_TRANSFORM IF_ASH_BASH_COMPAT
/* BASH_TEST2: [[ EXPR ]]
* Status of [[ support:
* && and || work as they should
@@ -574,6 +576,7 @@ var_end(const char *var)
return var;
}
+static int hasmeta(const char *);
/* ============ Parser data */
@@ -868,6 +871,9 @@ out2str(const char *p)
#define VSREPLACE 0xd /* ${var/pattern/replacement} */
#define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
#endif
+#if BASH_PARAM_TRANSFORM
+#define VSTRANSFORM 0xf /* ${var at operator} */
+#endif
static const char dolatstr[] ALIGN1 = {
CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
@@ -7262,6 +7268,20 @@ subevalvar(char *start, char *str, int strloc,
repl ? NULL : (slash_pos < 0 ? NULL : &slash_pos)
);
+#if BASH_PARAM_TRANSFORM
+ if (subtype == VSTRANSFORM) {
+ bb_error_msg("vstransform:str='%s'", str);
+ if (strcmp(str, "Q") != 0)
+ goto out1;
+ bb_error_msg("vstransform:startp='%s'", startp);
+ char *quoted = single_quote(startp);
+ int len = strlen(quoted);
+ memmove(startp, quoted, len);
+ loc = startp + len;
+ goto out;
+ }
+#endif /* BASH_PARAM_TRANSFORM */
+
#if BASH_PATTERN_SUBST
workloc = expdest - (char *)stackblock();
if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
@@ -7432,7 +7452,7 @@ subevalvar(char *start, char *str, int strloc,
out:
amount = loc - expdest;
STADJUST(amount, expdest);
-#if BASH_PATTERN_SUBST
+#if BASH_PATTERN_SUBST || BASH_PARAM_TRANSFORM
out1:
#endif
/* Remove any recorded regions beyond start of variable */
@@ -7671,6 +7691,9 @@ evalvar(char *p, int flag)
#if BASH_PATTERN_SUBST
case VSREPLACE:
case VSREPLACEALL:
+#endif
+#if BASH_PARAM_TRANSFORM
+ case VSTRANSFORM:
#endif
break;
default:
@@ -12989,6 +13012,13 @@ parsesub: {
goto badsub;
subtype++; /* VSREPLACEALL */
break;
+#endif
+#if BASH_PARAM_TRANSFORM
+ case '@':
+ /* ${v at operator} */
+ subtype = VSTRANSFORM;
+ newsyn = BASESYNTAX;
+ break;
#endif
}
} else {
On Thu, 15 Feb 2024, David Laight wrote:
> From: David Leonard
>> Sent: 15 February 2024 08:46
>> To: Harvey <harv at gmx.de>
>> Cc: busybox at busybox.net
>> Subject: Re: Failing shell code under busybox 1.36.1 that worked with 1.31.1
>>
>>
>>> _result="$_result '${_p//'/'\"'\"'}'"
>>
>> Busybox ash has a CONFIG_ASH_BASH_COMPAT config to get this ${var//...}
>> replacement behaviour. And, in bash, the ' in the pattern section is treated
>> as a quote start. To give the ' a literal meaning, use \'
>> eg ${_p//\'/..repl..}
> ...
>
> It is probably safer to the quotes into variables.
> Then the syntax analysis won't get messed up.
>
> So something like:
> sq="'"
> qsq='"'"'"'"'
>
> then
> "${_p/$sg/$qsq}"
>
> is probably ok and maybe more readable.
>
> David
>
> -
> Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
> Registration No: 1397386 (Wales)
>
More information about the busybox
mailing list