shell: better support of [[ ]] bashism
Still rather rudimentary for ash function old new delta binop 433 589 +156 check_operator 65 101 +36 done_word 736 769 +33 test_main 405 418 +13 parse_stream 2227 2238 +11 ops_texts 124 133 +9 ops_table 80 86 +6 run_pipe 1557 1562 +5 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 8/0 up/down: 269/0) Total: 269 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
112453acf2
commit
d2241f5902
@ -76,6 +76,8 @@
|
|||||||
//usage: "1\n"
|
//usage: "1\n"
|
||||||
|
|
||||||
#include "libbb.h"
|
#include "libbb.h"
|
||||||
|
#include <regex.h>
|
||||||
|
#include <fnmatch.h>
|
||||||
|
|
||||||
/* This is a NOFORK applet. Be very careful! */
|
/* This is a NOFORK applet. Be very careful! */
|
||||||
|
|
||||||
@ -146,6 +148,14 @@
|
|||||||
|
|
||||||
#define TEST_DEBUG 0
|
#define TEST_DEBUG 0
|
||||||
|
|
||||||
|
#if ENABLE_TEST2 \
|
||||||
|
|| (ENABLE_ASH_BASH_COMPAT && ENABLE_ASH_TEST) \
|
||||||
|
|| (ENABLE_HUSH_BASH_COMPAT && ENABLE_HUSH_TEST)
|
||||||
|
# define BASH_TEST2 1
|
||||||
|
#else
|
||||||
|
# define BASH_TEST2 0
|
||||||
|
#endif
|
||||||
|
|
||||||
enum token {
|
enum token {
|
||||||
EOI,
|
EOI,
|
||||||
|
|
||||||
@ -184,6 +194,10 @@ enum token {
|
|||||||
STRLT,
|
STRLT,
|
||||||
STRGT,
|
STRGT,
|
||||||
|
|
||||||
|
#if BASH_TEST2
|
||||||
|
REGEX,
|
||||||
|
#endif
|
||||||
|
|
||||||
INTEQ, /* int ops */
|
INTEQ, /* int ops */
|
||||||
INTNE,
|
INTNE,
|
||||||
INTGE,
|
INTGE,
|
||||||
@ -257,6 +271,9 @@ static const char *const TOKSTR[] = {
|
|||||||
"STRNE",
|
"STRNE",
|
||||||
"STRLT",
|
"STRLT",
|
||||||
"STRGT",
|
"STRGT",
|
||||||
|
#if BASH_TEST2
|
||||||
|
"REGEX",
|
||||||
|
#endif
|
||||||
"INTEQ",
|
"INTEQ",
|
||||||
"INTNE",
|
"INTNE",
|
||||||
"INTGE",
|
"INTGE",
|
||||||
@ -320,6 +337,9 @@ static const struct operator_t ops_table[] = {
|
|||||||
{ /* "!=" */ STRNE , BINOP },
|
{ /* "!=" */ STRNE , BINOP },
|
||||||
{ /* "<" */ STRLT , BINOP },
|
{ /* "<" */ STRLT , BINOP },
|
||||||
{ /* ">" */ STRGT , BINOP },
|
{ /* ">" */ STRGT , BINOP },
|
||||||
|
#if BASH_TEST2
|
||||||
|
{ /* "=~" */ REGEX , BINOP },
|
||||||
|
#endif
|
||||||
{ /* "-eq"*/ INTEQ , BINOP },
|
{ /* "-eq"*/ INTEQ , BINOP },
|
||||||
{ /* "-ne"*/ INTNE , BINOP },
|
{ /* "-ne"*/ INTNE , BINOP },
|
||||||
{ /* "-ge"*/ INTGE , BINOP },
|
{ /* "-ge"*/ INTGE , BINOP },
|
||||||
@ -332,6 +352,10 @@ static const struct operator_t ops_table[] = {
|
|||||||
{ /* "!" */ UNOT , BUNOP },
|
{ /* "!" */ UNOT , BUNOP },
|
||||||
{ /* "-a" */ BAND , BBINOP },
|
{ /* "-a" */ BAND , BBINOP },
|
||||||
{ /* "-o" */ BOR , BBINOP },
|
{ /* "-o" */ BOR , BBINOP },
|
||||||
|
#if BASH_TEST2
|
||||||
|
{ /* "&&" */ BAND , BBINOP },
|
||||||
|
{ /* "||" */ BOR , BBINOP },
|
||||||
|
#endif
|
||||||
{ /* "(" */ LPAREN , PAREN },
|
{ /* "(" */ LPAREN , PAREN },
|
||||||
{ /* ")" */ RPAREN , PAREN },
|
{ /* ")" */ RPAREN , PAREN },
|
||||||
};
|
};
|
||||||
@ -365,6 +389,9 @@ static const char ops_texts[] ALIGN1 =
|
|||||||
"!=" "\0"
|
"!=" "\0"
|
||||||
"<" "\0"
|
"<" "\0"
|
||||||
">" "\0"
|
">" "\0"
|
||||||
|
#if BASH_TEST2
|
||||||
|
"=~" "\0"
|
||||||
|
#endif
|
||||||
"-eq" "\0"
|
"-eq" "\0"
|
||||||
"-ne" "\0"
|
"-ne" "\0"
|
||||||
"-ge" "\0"
|
"-ge" "\0"
|
||||||
@ -377,6 +404,10 @@ static const char ops_texts[] ALIGN1 =
|
|||||||
"!" "\0"
|
"!" "\0"
|
||||||
"-a" "\0"
|
"-a" "\0"
|
||||||
"-o" "\0"
|
"-o" "\0"
|
||||||
|
#if BASH_TEST2
|
||||||
|
"&&" "\0"
|
||||||
|
"||" "\0"
|
||||||
|
#endif
|
||||||
"(" "\0"
|
"(" "\0"
|
||||||
")" "\0"
|
")" "\0"
|
||||||
;
|
;
|
||||||
@ -397,6 +428,9 @@ struct test_statics {
|
|||||||
const struct operator_t *last_operator;
|
const struct operator_t *last_operator;
|
||||||
gid_t *group_array;
|
gid_t *group_array;
|
||||||
int ngroups;
|
int ngroups;
|
||||||
|
#if BASH_TEST2
|
||||||
|
bool bash_test2;
|
||||||
|
#endif
|
||||||
jmp_buf leaving;
|
jmp_buf leaving;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -408,6 +442,7 @@ extern struct test_statics *const test_ptr_to_statics;
|
|||||||
#define last_operator (S.last_operator)
|
#define last_operator (S.last_operator)
|
||||||
#define group_array (S.group_array )
|
#define group_array (S.group_array )
|
||||||
#define ngroups (S.ngroups )
|
#define ngroups (S.ngroups )
|
||||||
|
#define bash_test2 (S.bash_test2 )
|
||||||
#define leaving (S.leaving )
|
#define leaving (S.leaving )
|
||||||
|
|
||||||
#define INIT_S() do { \
|
#define INIT_S() do { \
|
||||||
@ -501,6 +536,20 @@ static enum token check_operator(const char *s)
|
|||||||
n = index_in_strings(ops_texts, s);
|
n = index_in_strings(ops_texts, s);
|
||||||
if (n < 0)
|
if (n < 0)
|
||||||
return OPERAND;
|
return OPERAND;
|
||||||
|
|
||||||
|
#if BASH_TEST2
|
||||||
|
if (ops_table[n].op_num == REGEX && !bash_test2) {
|
||||||
|
/* =~ is only for [[ ]] */
|
||||||
|
return OPERAND;
|
||||||
|
}
|
||||||
|
if (ops_table[n].op_num == BAND || ops_table[n].op_num == BOR) {
|
||||||
|
/* [ ] accepts -a and -o but not && and || */
|
||||||
|
/* [[ ]] accepts && and || but not -a and -o */
|
||||||
|
if (bash_test2 == (s[0] == '-'))
|
||||||
|
return OPERAND;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
last_operator = &ops_table[n];
|
last_operator = &ops_table[n];
|
||||||
return ops_table[n].op_num;
|
return ops_table[n].op_num;
|
||||||
}
|
}
|
||||||
@ -536,6 +585,29 @@ static int binop(void)
|
|||||||
/*if (op->op_num == INTLT)*/
|
/*if (op->op_num == INTLT)*/
|
||||||
return val1 < val2;
|
return val1 < val2;
|
||||||
}
|
}
|
||||||
|
#if BASH_TEST2
|
||||||
|
if (bash_test2) {
|
||||||
|
if (op->op_num == STREQ) {
|
||||||
|
val1 = fnmatch(opnd2, opnd1, 0);
|
||||||
|
return val1 == 0;
|
||||||
|
}
|
||||||
|
if (op->op_num == STRNE) {
|
||||||
|
val1 = fnmatch(opnd2, opnd1, 0);
|
||||||
|
return val1 != 0;
|
||||||
|
}
|
||||||
|
if (op->op_num == REGEX) {
|
||||||
|
regex_t re_buffer;
|
||||||
|
memset(&re_buffer, 0, sizeof(re_buffer));
|
||||||
|
if (regcomp(&re_buffer, opnd2, REG_EXTENDED)) { // REG_NEWLINE?
|
||||||
|
/* Bad regex */
|
||||||
|
longjmp(leaving, 2); /* [[ a =~ * ]]; echo $? - prints 2 (silently, no error msg) */
|
||||||
|
}
|
||||||
|
val1 = regexec(&re_buffer, opnd1, 0, NULL, 0);
|
||||||
|
regfree(&re_buffer);
|
||||||
|
return val1 == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (is_str_op(op->op_num)) {
|
if (is_str_op(op->op_num)) {
|
||||||
val1 = strcmp(opnd1, opnd2);
|
val1 = strcmp(opnd1, opnd2);
|
||||||
if (op->op_num == STREQ)
|
if (op->op_num == STREQ)
|
||||||
@ -824,6 +896,9 @@ int test_main(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
const char *arg0;
|
const char *arg0;
|
||||||
|
#if BASH_TEST2
|
||||||
|
bool bt2 = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
arg0 = bb_basename(argv[0]);
|
arg0 = bb_basename(argv[0]);
|
||||||
if ((ENABLE_TEST1 || ENABLE_TEST2 || ENABLE_ASH_TEST || ENABLE_HUSH_TEST)
|
if ((ENABLE_TEST1 || ENABLE_TEST2 || ENABLE_ASH_TEST || ENABLE_HUSH_TEST)
|
||||||
@ -840,6 +915,9 @@ int test_main(int argc, char **argv)
|
|||||||
bb_simple_error_msg("missing ]]");
|
bb_simple_error_msg("missing ]]");
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
#if BASH_TEST2
|
||||||
|
bt2 = 1;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
argv[argc] = NULL;
|
argv[argc] = NULL;
|
||||||
}
|
}
|
||||||
@ -848,6 +926,10 @@ int test_main(int argc, char **argv)
|
|||||||
/* We must do DEINIT_S() prior to returning */
|
/* We must do DEINIT_S() prior to returning */
|
||||||
INIT_S();
|
INIT_S();
|
||||||
|
|
||||||
|
#if BASH_TEST2
|
||||||
|
bash_test2 = bt2;
|
||||||
|
#endif
|
||||||
|
|
||||||
res = setjmp(leaving);
|
res = setjmp(leaving);
|
||||||
if (res)
|
if (res)
|
||||||
goto ret;
|
goto ret;
|
||||||
|
15
shell/ash.c
15
shell/ash.c
@ -207,17 +207,17 @@
|
|||||||
#define IF_BASH_SUBSTR IF_ASH_BASH_COMPAT
|
#define IF_BASH_SUBSTR IF_ASH_BASH_COMPAT
|
||||||
/* BASH_TEST2: [[ EXPR ]]
|
/* BASH_TEST2: [[ EXPR ]]
|
||||||
* Status of [[ support:
|
* Status of [[ support:
|
||||||
* We replace && and || with -a and -o
|
* && and || work as they should
|
||||||
|
* = is glob match operator, not equality operator: STR = GLOB
|
||||||
|
* (in GLOB, quoting is significant on char-by-char basis: a*cd"*")
|
||||||
|
* == same as =
|
||||||
|
* add =~ regex match operator: STR =~ REGEX
|
||||||
* TODO:
|
* TODO:
|
||||||
* singleword+noglob expansion:
|
* singleword+noglob expansion:
|
||||||
* v='a b'; [[ $v = 'a b' ]]; echo 0:$?
|
* v='a b'; [[ $v = 'a b' ]]; echo 0:$?
|
||||||
* [[ /bin/n* ]]; echo 0:$?
|
* [[ /bin/n* ]]; echo 0:$?
|
||||||
* -a/-o are not AND/OR ops! (they are just strings)
|
|
||||||
* quoting needs to be considered (-f is an operator, "-f" and ""-f are not; etc)
|
* quoting needs to be considered (-f is an operator, "-f" and ""-f are not; etc)
|
||||||
* = is glob match operator, not equality operator: STR = GLOB
|
* ( ) < > should not have special meaning
|
||||||
* (in GLOB, quoting is significant on char-by-char basis: a*cd"*")
|
|
||||||
* == same as =
|
|
||||||
* add =~ regex match operator: STR =~ REGEX
|
|
||||||
*/
|
*/
|
||||||
#define BASH_TEST2 (ENABLE_ASH_BASH_COMPAT * ENABLE_ASH_TEST)
|
#define BASH_TEST2 (ENABLE_ASH_BASH_COMPAT * ENABLE_ASH_TEST)
|
||||||
#define BASH_SOURCE ENABLE_ASH_BASH_COMPAT
|
#define BASH_SOURCE ENABLE_ASH_BASH_COMPAT
|
||||||
@ -11823,7 +11823,8 @@ simplecmd(void)
|
|||||||
tokpushback = 1;
|
tokpushback = 1;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
wordtext = (char *) (t == TAND ? "-a" : "-o");
|
/* pass "&&" or "||" to [[ ]] as literal args */
|
||||||
|
wordtext = (char *) (t == TAND ? "&&" : "||");
|
||||||
#endif
|
#endif
|
||||||
case TWORD:
|
case TWORD:
|
||||||
n = stzalloc(sizeof(struct narg));
|
n = stzalloc(sizeof(struct narg));
|
||||||
|
57
shell/hush.c
57
shell/hush.c
@ -84,13 +84,12 @@
|
|||||||
* [[ args ]] are CMD_SINGLEWORD_NOGLOB:
|
* [[ args ]] are CMD_SINGLEWORD_NOGLOB:
|
||||||
* v='a b'; [[ $v = 'a b' ]]; echo 0:$?
|
* v='a b'; [[ $v = 'a b' ]]; echo 0:$?
|
||||||
* [[ /bin/n* ]]; echo 0:$?
|
* [[ /bin/n* ]]; echo 0:$?
|
||||||
|
* = is glob match operator, not equality operator: STR = GLOB
|
||||||
|
* (in GLOB, quoting is significant on char-by-char basis: a*cd"*")
|
||||||
|
* == same as =
|
||||||
|
* =~ is regex match operator: STR =~ REGEX
|
||||||
* TODO:
|
* TODO:
|
||||||
* &&/|| are AND/OR ops, -a/-o are not
|
|
||||||
* quoting needs to be considered (-f is an operator, "-f" and ""-f are not; etc)
|
* quoting needs to be considered (-f is an operator, "-f" and ""-f are not; etc)
|
||||||
* = is glob match operator, not equality operator: STR = GLOB
|
|
||||||
* (in GLOB, quoting is significant on char-by-char basis: a*cd"*")
|
|
||||||
* == same as =
|
|
||||||
* add =~ regex match operator: STR =~ REGEX
|
|
||||||
*/
|
*/
|
||||||
//config:config HUSH
|
//config:config HUSH
|
||||||
//config: bool "hush (68 kb)"
|
//config: bool "hush (68 kb)"
|
||||||
@ -651,14 +650,16 @@ struct command {
|
|||||||
smallint cmd_type; /* CMD_xxx */
|
smallint cmd_type; /* CMD_xxx */
|
||||||
#define CMD_NORMAL 0
|
#define CMD_NORMAL 0
|
||||||
#define CMD_SUBSHELL 1
|
#define CMD_SUBSHELL 1
|
||||||
#if BASH_TEST2 || ENABLE_HUSH_LOCAL || ENABLE_HUSH_EXPORT || ENABLE_HUSH_READONLY
|
#if BASH_TEST2
|
||||||
/* used for "[[ EXPR ]]", and to prevent word splitting and globbing in
|
/* used for "[[ EXPR ]]" */
|
||||||
* "export v=t*"
|
# define CMD_TEST2_SINGLEWORD_NOGLOB 2
|
||||||
*/
|
#endif
|
||||||
# define CMD_SINGLEWORD_NOGLOB 2
|
#if ENABLE_HUSH_LOCAL || ENABLE_HUSH_EXPORT || ENABLE_HUSH_READONLY
|
||||||
|
/* used to prevent word splitting and globbing in "export v=t*" */
|
||||||
|
# define CMD_SINGLEWORD_NOGLOB 3
|
||||||
#endif
|
#endif
|
||||||
#if ENABLE_HUSH_FUNCTIONS
|
#if ENABLE_HUSH_FUNCTIONS
|
||||||
# define CMD_FUNCDEF 3
|
# define CMD_FUNCDEF 4
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
smalluint cmd_exitcode;
|
smalluint cmd_exitcode;
|
||||||
@ -4111,6 +4112,14 @@ static int done_word(struct parse_context *ctx)
|
|||||||
/* ctx->ctx_res_w = RES_MATCH; */
|
/* ctx->ctx_res_w = RES_MATCH; */
|
||||||
ctx->ctx_dsemicolon = 0;
|
ctx->ctx_dsemicolon = 0;
|
||||||
} else
|
} else
|
||||||
|
# endif
|
||||||
|
# if defined(CMD_TEST2_SINGLEWORD_NOGLOB)
|
||||||
|
if (command->cmd_type == CMD_TEST2_SINGLEWORD_NOGLOB
|
||||||
|
&& strcmp(ctx->word.data, "]]") == 0
|
||||||
|
) {
|
||||||
|
/* allow "[[ ]] >file" etc */
|
||||||
|
command->cmd_type = CMD_SINGLEWORD_NOGLOB;
|
||||||
|
} else
|
||||||
# endif
|
# endif
|
||||||
if (!command->argv /* if it's the first word... */
|
if (!command->argv /* if it's the first word... */
|
||||||
# if ENABLE_HUSH_LOOPS
|
# if ENABLE_HUSH_LOOPS
|
||||||
@ -4146,11 +4155,13 @@ static int done_word(struct parse_context *ctx)
|
|||||||
(ctx->ctx_res_w == RES_SNTX));
|
(ctx->ctx_res_w == RES_SNTX));
|
||||||
return (ctx->ctx_res_w == RES_SNTX);
|
return (ctx->ctx_res_w == RES_SNTX);
|
||||||
}
|
}
|
||||||
|
# if defined(CMD_TEST2_SINGLEWORD_NOGLOB)
|
||||||
|
if (strcmp(ctx->word.data, "[[") == 0) {
|
||||||
|
command->cmd_type = CMD_TEST2_SINGLEWORD_NOGLOB;
|
||||||
|
} else
|
||||||
|
# endif
|
||||||
# if defined(CMD_SINGLEWORD_NOGLOB)
|
# if defined(CMD_SINGLEWORD_NOGLOB)
|
||||||
if (0
|
if (0
|
||||||
# if BASH_TEST2
|
|
||||||
|| strcmp(ctx->word.data, "[[") == 0
|
|
||||||
# endif
|
|
||||||
/* In bash, local/export/readonly are special, args
|
/* In bash, local/export/readonly are special, args
|
||||||
* are assignments and therefore expansion of them
|
* are assignments and therefore expansion of them
|
||||||
* should be "one-word" expansion:
|
* should be "one-word" expansion:
|
||||||
@ -4172,7 +4183,8 @@ static int done_word(struct parse_context *ctx)
|
|||||||
) {
|
) {
|
||||||
command->cmd_type = CMD_SINGLEWORD_NOGLOB;
|
command->cmd_type = CMD_SINGLEWORD_NOGLOB;
|
||||||
}
|
}
|
||||||
/* fall through */
|
# else
|
||||||
|
{ /* empty block to pair "if ... else" */ }
|
||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
#endif /* HAS_KEYWORDS */
|
#endif /* HAS_KEYWORDS */
|
||||||
@ -5354,9 +5366,15 @@ static struct pipe *parse_stream(char **pstring,
|
|||||||
if (ch != '\n')
|
if (ch != '\n')
|
||||||
next = i_peek_and_eat_bkslash_nl(input);
|
next = i_peek_and_eat_bkslash_nl(input);
|
||||||
|
|
||||||
is_special = "{}<>;&|()#" /* special outside of "str" */
|
is_special = "{}<>&|();#" /* special outside of "str" */
|
||||||
"$\"" IF_HUSH_TICK("`") /* always special */
|
"$\"" IF_HUSH_TICK("`") /* always special */
|
||||||
SPECIAL_VAR_SYMBOL_STR;
|
SPECIAL_VAR_SYMBOL_STR;
|
||||||
|
#if defined(CMD_TEST2_SINGLEWORD_NOGLOB)
|
||||||
|
if (ctx.command->cmd_type == CMD_TEST2_SINGLEWORD_NOGLOB) {
|
||||||
|
/* In [[ ]], {}<>&|() are not special */
|
||||||
|
is_special += 8;
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
/* Are { and } special here? */
|
/* Are { and } special here? */
|
||||||
if (ctx.command->argv /* word [word]{... - non-special */
|
if (ctx.command->argv /* word [word]{... - non-special */
|
||||||
|| ctx.word.length /* word{... - non-special */
|
|| ctx.word.length /* word{... - non-special */
|
||||||
@ -6953,7 +6971,7 @@ static char **expand_strvec_to_strvec(char **argv)
|
|||||||
return expand_variables(argv, EXP_FLAG_GLOB | EXP_FLAG_ESC_GLOB_CHARS);
|
return expand_variables(argv, EXP_FLAG_GLOB | EXP_FLAG_ESC_GLOB_CHARS);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CMD_SINGLEWORD_NOGLOB)
|
#if defined(CMD_SINGLEWORD_NOGLOB) || defined(CMD_TEST2_SINGLEWORD_NOGLOB)
|
||||||
static char **expand_strvec_to_strvec_singleword_noglob(char **argv)
|
static char **expand_strvec_to_strvec_singleword_noglob(char **argv)
|
||||||
{
|
{
|
||||||
return expand_variables(argv, EXP_FLAG_SINGLEWORD);
|
return expand_variables(argv, EXP_FLAG_SINGLEWORD);
|
||||||
@ -9133,6 +9151,11 @@ static NOINLINE int run_pipe(struct pipe *pi)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Expand the rest into (possibly) many strings each */
|
/* Expand the rest into (possibly) many strings each */
|
||||||
|
#if defined(CMD_TEST2_SINGLEWORD_NOGLOB)
|
||||||
|
if (command->cmd_type == CMD_TEST2_SINGLEWORD_NOGLOB)
|
||||||
|
argv_expanded = expand_strvec_to_strvec_singleword_noglob(argv + command->assignment_cnt);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
#if defined(CMD_SINGLEWORD_NOGLOB)
|
#if defined(CMD_SINGLEWORD_NOGLOB)
|
||||||
if (command->cmd_type == CMD_SINGLEWORD_NOGLOB)
|
if (command->cmd_type == CMD_SINGLEWORD_NOGLOB)
|
||||||
argv_expanded = expand_strvec_to_strvec_singleword_noglob(argv + command->assignment_cnt);
|
argv_expanded = expand_strvec_to_strvec_singleword_noglob(argv + command->assignment_cnt);
|
||||||
|
6
shell/hush_test/hush-test2/andor1.right
Normal file
6
shell/hush_test/hush-test2/andor1.right
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
1:YES
|
||||||
|
2:no
|
||||||
|
3:YES
|
||||||
|
4:YES
|
||||||
|
5:no
|
||||||
|
6:no
|
7
shell/hush_test/hush-test2/andor1.tests
Executable file
7
shell/hush_test/hush-test2/andor1.tests
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
e=''
|
||||||
|
[[ a && b ]] && echo 1:YES
|
||||||
|
[[ a && '' ]] || echo 2:no
|
||||||
|
[[ a || b ]] && echo 3:YES
|
||||||
|
[[ '' || b ]] && echo 4:YES
|
||||||
|
[[ "" || "$e" ]] || echo 5:no
|
||||||
|
[[ "" || $e ]] || echo 6:no
|
2
shell/hush_test/hush-test2/noglob1.right
Normal file
2
shell/hush_test/hush-test2/noglob1.right
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
1:YES:0
|
||||||
|
2:YES:0
|
3
shell/hush_test/hush-test2/noglob1.tests
Executable file
3
shell/hush_test/hush-test2/noglob1.tests
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
v='*.tests'
|
||||||
|
[[ *.tests ]]; echo 1:YES:$?
|
||||||
|
[[ $v ]]; echo 2:YES:$?
|
8
shell/hush_test/hush-test2/strops1.right
Normal file
8
shell/hush_test/hush-test2/strops1.right
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
1:YES:0
|
||||||
|
2:YES:0
|
||||||
|
3:YES:0
|
||||||
|
4:YES:0
|
||||||
|
5:YES:0
|
||||||
|
6:YES:0
|
||||||
|
7:YES:0
|
||||||
|
8:no:1
|
15
shell/hush_test/hush-test2/strops1.tests
Executable file
15
shell/hush_test/hush-test2/strops1.tests
Executable file
@ -0,0 +1,15 @@
|
|||||||
|
v='*.z'
|
||||||
|
[[ a.z = *.z ]]; echo 1:YES:$?
|
||||||
|
[[ a.z == $v ]]; echo 2:YES:$?
|
||||||
|
|
||||||
|
# wildcards can match a slash
|
||||||
|
[[ a/b = a*b ]]; echo 3:YES:$?
|
||||||
|
[[ a/b == a?b ]]; echo 4:YES:$?
|
||||||
|
|
||||||
|
# wildcards can match a leading dot
|
||||||
|
[[ a/.b = a/*b ]]; echo 5:YES:$?
|
||||||
|
[[ a/.b == a/?b ]]; echo 6:YES:$?
|
||||||
|
|
||||||
|
# wildcards can be escaped
|
||||||
|
[[ abc = a*c ]]; echo 7:YES:$?
|
||||||
|
[[ abc == a\*c ]]; echo 8:no:$?
|
6
shell/hush_test/hush-test2/strops2.right
Normal file
6
shell/hush_test/hush-test2/strops2.right
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
1:ERR2:2
|
||||||
|
2:YES:0
|
||||||
|
3:YES:0
|
||||||
|
4:YES:0
|
||||||
|
5:no:1
|
||||||
|
6:YES:0
|
12
shell/hush_test/hush-test2/strops2.tests
Executable file
12
shell/hush_test/hush-test2/strops2.tests
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
# malformed regex
|
||||||
|
[[ a =~ * ]]; echo 1:ERR2:$?
|
||||||
|
|
||||||
|
[[ a/b =~ a.b ]]; echo 2:YES:$?
|
||||||
|
[[ a/b =~ /*b ]]; echo 3:YES:$?
|
||||||
|
|
||||||
|
v='[]b.-]'
|
||||||
|
[[ a/.b] =~ $v ]]; echo 4:YES:$?
|
||||||
|
|
||||||
|
v=']b.-'
|
||||||
|
[[ a/.b] =~ $v ]]; echo 5:no:$?
|
||||||
|
[[ a/.b] =~ [$v] ]]; echo 6:YES:$?
|
7
shell/hush_test/hush-test2/strops3.right
Normal file
7
shell/hush_test/hush-test2/strops3.right
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
1:YES:0
|
||||||
|
2:YES:0
|
||||||
|
3:no:1
|
||||||
|
4:YES:0
|
||||||
|
2u:YES:0
|
||||||
|
3u:YES:0
|
||||||
|
4u:YES:0
|
13
shell/hush_test/hush-test2/strops3.tests
Executable file
13
shell/hush_test/hush-test2/strops3.tests
Executable file
@ -0,0 +1,13 @@
|
|||||||
|
# regex should accept '+' operator
|
||||||
|
[[ abcdef =~ a[b-z]+ ]]; echo 1:YES:$?
|
||||||
|
|
||||||
|
# newline matches by "match any" patterns
|
||||||
|
v='
|
||||||
|
'
|
||||||
|
[[ "$v" =~ . ]]; echo 2:YES:$?
|
||||||
|
[[ "$v" =~ "[$v]" ]]; echo 3:no:$? # hmm bash does return 1... why?
|
||||||
|
[[ "$v" =~ [^a] ]]; echo 4:YES:$?
|
||||||
|
# should work even without quotes:
|
||||||
|
[[ $v =~ . ]]; echo 2u:YES:$?
|
||||||
|
[[ $v =~ [$v] ]]; echo 3u:YES:$?
|
||||||
|
[[ $v =~ [^a] ]]; echo 4u:YES:$?
|
Loading…
Reference in New Issue
Block a user