git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 6/6] always quote shell arguments to test -z/-n

From
Jeff King <peff@peff.net>
Date
May 13, 2016, 20:47 UTC
Message-ID
<20160513204732.GF15391@sigill.intra.peff.net>
In-Reply-To
<20160513204654.GA10684@sigill.intra.peff.net>
In shell code like:
  test -z $foo
  test -n $foo

that does not quote its arguments, it's easy to think that it is actually looking at the contents of $foo in each case. But if $foo is empty, then "test" does not see any argument at all! The results are quite subtle.

POSIX specifies that test's behavior depends on the number of arguments it sees, and if $foo is empty, it sees only one. The behavior in this case is:

  1 argument: Exit true (0) if $1 is not null; otherwise,
              exit false.

So in the "-z $foo" case, if $foo is empty, then we check that "-z" is non-null, and it returns success. Which happens to match what we expected. But for "-n $foo", if $foo is empty, we'll see that "-n" is non-null and still return success. That's the opposite of what we intended!

Furthermore, if $foo contains whitespace, we'll end up with more than 2 arguments. The results in this case are generally unspecified (unless the first part of $foo happens to be a valid binary operator, in which case the results are specified but certainly not what we intended).

And on top of this, even though "test -z $foo" _should_ work for the empty case, some older shells (reportedly ksh88) complain about the missing argument.

So let's make sure we consistently quote our variable arguments to "test". After this patch, the results of:

  git grep 'test -[zn] [^"]'
are empty.
Reported-by: Armin Kunaschik <megabreit@googlemail.com>
Helped-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Jeff King <peff@peff.net>
---
 git-rebase--interactive.sh | 4 ++--
 git-stash.sh               | 4 ++--
 t/t4151-am-abort.sh        | 2 +-
 3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 9ea3075..470413b 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -866,12 +866,12 @@ add_exec_commands () {
 # $3: the input filename
 check_commit_sha () {
 	badsha=0
-	if test -z $1
+	if test -z "$1"
 	then
 		badsha=1
 	else
 		sha1_verif="$(git rev-parse --verify --quiet $1^{commit})"
-		if test -z $sha1_verif
+		if test -z "$sha1_verif"
 		then
 			badsha=1
 		fi
diff --git a/git-stash.sh b/git-stash.sh
index c7c65e2..c7509e8 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -185,7 +185,7 @@ store_stash () {
 
 	git update-ref --create-reflog -m "$stash_msg" $ref_stash $w_commit
 	ret=$?
-	test $ret != 0 && test -z $quiet &&
+	test $ret != 0 && test -z "$quiet" &&
 	die "$(eval_gettext "Cannot update \$ref_stash with \$w_commit")"
 	return $ret
 }
@@ -277,7 +277,7 @@ save_stash () {
 			git clean --force --quiet -d $CLEAN_X_OPTION
 		fi
 
-		if test "$keep_index" = "t" && test -n $i_tree
+		if test "$keep_index" = "t" && test -n "$i_tree"
 		then
 			git read-tree --reset -u $i_tree
 		fi
diff --git a/t/t4151-am-abort.sh b/t/t4151-am-abort.sh
index ea5ace9..9473c27 100755
--- a/t/t4151-am-abort.sh
+++ b/t/t4151-am-abort.sh
@@ -82,7 +82,7 @@ test_expect_success 'am -3 --abort removes otherfile-4' '
 	test 4 = "$(cat otherfile-4)" &&
 	git am --abort &&
 	test_cmp_rev initial HEAD &&
-	test -z $(git ls-files -u) &&
+	test -z "$(git ls-files -u)" &&
 	test_path_is_missing otherfile-4
 '
 
-- 
2.8.2.825.gea31738
Previous: Jeff KingNext: Junio C Hamano
Message 18 of 19 in “t3404 static check of bad SHA-1 failure”
  1. Armin KunaschikMay 13, 2016
  2. Jeff KingMay 13, 2016
  3. Junio C HamanoMay 13, 2016
  4. Jeff KingMay 13, 2016
  5. Jeff KingMay 13, 2016
  6. Junio C HamanoMay 13, 2016
  7. 0/6 test -z/-n quoting fix + misc cleanupsJeff King, May 13, 2016
  8. 1/6 t/lib-git-svn: drop $remote_git_svn and $git_svn_idJeff King, May 13, 2016
  9. 2/6 t9100,t3419: enclose all test code in single-quotesJeff King, May 13, 2016
  10. 3/6 t9107: use "return 1" instead of "exit 1"Jeff King, May 13, 2016
  11. Eric WongMay 13, 2016
  12. Eric SunshineMay 13, 2016
  13. Jeff KingMay 13, 2016
  14. Junio C HamanoMay 14, 2016
  15. Jeff KingMay 14, 2016
  16. 4/6 t9107: switch inverted single/double quotes in testJeff King, May 13, 2016
  17. 5/6 t9103: modernize test styleJeff King, May 13, 2016
  18. 6/6 always quote shell arguments to test -z/-nJeff King, May 13, 2016
  19. Junio C HamanoMay 13, 2016

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.