Skip to main content

Beware of using test -n with command expansion

I’d written a fish script that used test -n (check for an empty string) and a command substitution, but I was seeing unexpected results:

if test -n (which keyring)
    echo "I know where keyring is!"
end

In particular, it would always execute the “true” body of the if statement, even if which keyring returned an empty string.

This is because of the way fish’s shell expansion work – the which keyring gets reduced to nothing, and then it becomes test -n which is always true. There’s a long discussion of this in a GitHub ticket “test -n not working as expected”.

You can see this more clearly in this example:

if test -n (printf "")
    echo "It's not empty!"
end

The fix is to assign the command substitution to a variable first, then check whether that’s an empty string. For example:

set location (which keyring)

if test -n "$location"
    echo "I know where keyring is"
end

or to do some other test on the output; in this case I decided to check the $status variable of the which command.