From fc8bf9a984c118d551b3f93c66f1ae2733b9b588 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Thu, 12 Mar 2026 11:01:03 +0100 Subject: cmd: test: allow using [ as alias for test I often find myself writing something like if [ "$somevar" = 123 ] ; then ... only to realize that that syntax doesn't work in U-Boot shell, and must be spelled if test "$somevar" = 123 ; then It only takes a few lines of code to support this POSIX-standardized alias for test, and helps developers focus on their actual problems instead of dealing with such unexpected quirks of the shell. Signed-off-by: Rasmus Villemoes Tested-by: Anshul Dalal --- cmd/test.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'cmd') diff --git a/cmd/test.c b/cmd/test.c index a9ac07e6143..f0645ef98f1 100644 --- a/cmd/test.c +++ b/cmd/test.c @@ -63,6 +63,14 @@ static int do_test(struct cmd_tbl *cmdtp, int flag, int argc, char * const *ap; int i, op, left, adv, expr, last_expr, last_unop, last_binop; + if (!strcmp(argv[0], "[")) { + if (strcmp(argv[argc - 1], "]")) { + printf("[: missing terminating ]\n"); + return 1; + } + argc--; + } + /* args? */ if (argc < 3) return 1; @@ -212,6 +220,17 @@ U_BOOT_CMD( "[args..]" ); +/* + * This does not use the U_BOOT_CMD macro as [ can't be used in symbol names + */ +ll_entry_declare(struct cmd_tbl, lbracket, cmd) = { + "[", CONFIG_SYS_MAXARGS, cmd_always_repeatable, do_test, + "alias for 'test'", +#ifdef CONFIG_SYS_LONGHELP + " ]" +#endif /* CONFIG_SYS_LONGHELP */ +}; + static int do_false(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { -- cgit v1.3.1 From 8b0619579b2282050e7fb0d92fbc645b79d18bae Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Thu, 12 Mar 2026 11:01:06 +0100 Subject: cmd: test: fix handling of single-argument form of test POSIX states that 0 arguments: Exit false (1). 1 argument: Exit true (0) if $1 is not null; otherwise, exit false. and at least bash and busybox sh behave that way. The current 'argc < 3' does the right thing for a non-existing or empty argv[1], but not for a non-empty argv[1]. Fix that and add corresponding test cases. Signed-off-by: Rasmus Villemoes Tested-by: Anshul Dalal --- cmd/test.c | 11 +++++++++-- test/hush/if.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) (limited to 'cmd') diff --git a/cmd/test.c b/cmd/test.c index f0645ef98f1..0d0f090386c 100644 --- a/cmd/test.c +++ b/cmd/test.c @@ -71,10 +71,17 @@ static int do_test(struct cmd_tbl *cmdtp, int flag, int argc, argc--; } - /* args? */ - if (argc < 3) + /* + * Per POSIX, 'test' with 0 arguments should return 1, while + * 'test ' should be equivalent to 'test -n ', + * i.e. true if and only if is not empty. + */ + if (argc < 2) return 1; + if (argc == 2) + return !strcmp(argv[1], ""); + #ifdef DEBUG { debug("test(%d):", argc); diff --git a/test/hush/if.c b/test/hush/if.c index 5f75ea68b32..6129e2c530c 100644 --- a/test/hush/if.c +++ b/test/hush/if.c @@ -32,6 +32,15 @@ static int hush_test_if_base(struct unit_test_state *uts) sprintf(if_formatted, if_format, "false"); ut_asserteq(1, run_command(if_formatted, 0)); + sprintf(if_formatted, if_format, "test"); + ut_asserteq(1, run_command(if_formatted, 0)); + + sprintf(if_formatted, if_format, "test ''"); + ut_asserteq(1, run_command(if_formatted, 0)); + + sprintf(if_formatted, if_format, "test 'abc'"); + ut_assertok(run_command(if_formatted, 0)); + return 0; } HUSH_TEST(hush_test_if_base, 0); @@ -355,6 +364,27 @@ static int hush_test_lbracket_alias(struct unit_test_state *uts) sprintf(if_formatted, if_format, "[ ! aaa != aaa -o ! bbb = bbb ]"); ut_assertok(run_command(if_formatted, 0)); + sprintf(if_formatted, if_format, "[ ]"); + ut_asserteq(1, run_command(if_formatted, 0)); + + sprintf(if_formatted, if_format, "["); + ut_asserteq(1, run_command(if_formatted, 0)); + ut_assert_nextline(missing_rbracket_error); + + sprintf(if_formatted, if_format, "[ '' ]"); + ut_asserteq(1, run_command(if_formatted, 0)); + + sprintf(if_formatted, if_format, "[ ''"); + ut_asserteq(1, run_command(if_formatted, 0)); + ut_assert_nextline(missing_rbracket_error); + + sprintf(if_formatted, if_format, "[ 'abc' ]"); + ut_assertok(run_command(if_formatted, 0)); + + sprintf(if_formatted, if_format, "[ 'abc'"); + ut_asserteq(1, run_command(if_formatted, 0)); + ut_assert_nextline(missing_rbracket_error); + return 0; } HUSH_TEST(hush_test_lbracket_alias, UTF_CONSOLE); -- cgit v1.3.1