I've got a command that is working when run as the current user but if I prefix sudo to the command, it gives me an error.

I'm trying to remove a file if it's a directory (but not if it's a symlink to a directory). This works great:

brad@ip-10-0-0-1:~$ [[ -d /path/to/my/place && ! -L /path/to/my/place ]] && rm -rf /path/to/my/place

But if I try to use sudo to do this as a super user I get an error because sudo seems to think [[ is a command:

brad@ip-10-0-0-1:~$ sudo [[ -d /path/to/my/place && ! -L /path/to/my/place ]] && rm -rf /path/to/my/place
sudo: [[: command not found

I had to add the double brackets to get the ! -L /path/to/my/place bit to work; sudo was working fine with single brackets before when I was running

brad@ip-10-0-0-1:~$ sudo [ -d /path/to/my/place ] && rm -rf /path/to/my/place

But now that I'm trying to check to ensure it's not a symlink I can't get it to work with sudo. How can I either:

  • Get the double bracket syntax to work with sudo or
  • Get the single bracket syntax to allow me to negate the -L portion?
$ type -a [
[ is a shell builtin
[ is /usr/bin/[
$ type -a [[
[[ is a shell keyword

As you can see [ (beside being a shell builtin) is a regular command that sudo can use. [[ is not. You need bash to provide [[:

sudo bash -c '[[ -d /path/to/my/place && ! -L /path/to/my/place ]]' && …

Because [[ is a shell keyword, the parser recognizes it and changes the behavior of && between [[ and ]]. You cannot use && inside [ … ] because [ acts as a command and ] is in fact the last argument passed to it. Having && inside means there are two commands which is wrong.

However [ supports -a, so this may work:

sudo [ -d /path/to/my/place -a ! -L /path/to/my/place ] && …

You should avoid it though. From this article:

The binary -a and -o […] are XSI extensions to the POSIX standard. All are marked as obsolescent in POSIX-2008. They should not be used in new code. One of the practical problems with [ A = B -a C = D ] (or -o) is that POSIX does not specify the results of a test or [ command with more than 4 arguments. It probably works in most shells, but you can't count on it. If you have to write for POSIX shells, then you should use two test or [ commands separated by a && operator instead.

So this should be safer if you want to use [:

sudo [ -d /path/to/my/place ] && sudo [ ! -L /path/to/my/place ] && …
  • Excellent! sudo bash -c ... Worked like a charm. Thanks. – Brad Dwyer Oct 12 '18 at 20:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.