11

I want to create a shell script that echos something if 3 directories don't exist.

Here is the code I wrote: test.sh:

if [ ! -d "/home/unix/POSTagger2" ] || [! -d "/home/unix/POSTagger2/stanford-parser-full-2015-12-09"] || [! -d "/home/unix/POSTagger2/stanford-corenlp-full-2015-12-09"]; then
echo "Nope"
fi

When I run it, I get this error:

./test.sh: line 1: [!: command not found

What's wrong with my syntax?

2
  • In the first condition, you had it right. Doing the same in the second condition would be the first thing which I would have done…
    – glglgl
    Jul 21, 2016 at 7:51
  • [ is not a token, it is a command (another name for the command test) as such it must be separated by space(s). Similar case is ] which is a command parameter so it must be separated by a space too. Jul 21, 2016 at 13:50

2 Answers 2

17

You are missing some spaces, for example [! must be [ ! and "] must be " ] look to the corrected code:

#!/bin/bash
if 
[ ! -d "/home/unix/POSTagger2" ] || 
[ ! -d "/home/unix/POSTagger2/stanford-parser-full-2015-12-09" ] || 
[ ! -d "/home/unix/POSTagger2/stanford-corenlp-full-2015-12-09" ] 
then
      echo "Nope"
fi

Another way for your code:

#!/bin/bash
for dir in "/home/unix/POSTagger2" "/home/unix/POSTagger2/stanford-parser-full-2015-12-09" "/home/unix/POSTagger2/stanford-corenlp-full-2015-12-09"; do
     if [ ! -d "$dir" ]; then echo nope ; break; fi 
done  
1
  • bash is not the only shell in unix. There is pure shell /bin/sh
    – Igor
    Sep 12, 2022 at 9:44
9

You need a space between the [ and the ! for things to work correctly. This is because [ is implemented as shell-builtin command (it even used to be a separate exectuable /usr/bin/[).

You can also use:

if [ ! -d "/home/unix/POSTagger2" -o ! -d "/home/unix/POSTagger2/stanford-parser-full-2015-12-09" -o ! -d "/home/unix/POSTagger2/stanford-corenlp-full-2015-12-09") ] ; then
    echo "Nope"
fi

Bash offers an alternative [[ that is implemented as en expression. [[ uses &&, ||, etc. instead of -a, -o as operators.

if [[ ! (-d "/home/unix/POSTagger2" && -d "/home/unix/POSTagger2/stanford-parser-full-2015-12-09" && -d "/home/unix/POSTagger2/stanford-corenlp-full-2015-12-09") ]] ; then
    echo yes
fi

Edit: Thanks to comments from @LucianoAndressMartini and @pabouk for important corrections to my understanding.

8
  • 1
    No! You're wrong. Try moving out the /usr/bin/[ to other folder, and you see that the conditional statement still works fine because its a bash built-in, this executable you see is not being used by bash, it is offered as a compatibility option for some ancient shell, so they can run some bash code without errors. Jul 20, 2016 at 18:47
  • 3
    It's a builtin command in bash, but the fact that it acts like any command and needs a space still applies.
    – ilkkachu
    Jul 20, 2016 at 18:49
  • 1
    Yes this part of the answer still applies. It is a great answer, the only wrong thing is about thinking that "[" is not a shell built-in. Jul 20, 2016 at 18:50
  • 1
    Well I learned something new! I never revised my view of [ since 1999, apparently. Jul 20, 2016 at 20:50
  • 1
    [[ is not a command. It is a token and some special characters have a different meaning between [[ and ]]. Also it is not POSIX-compliant and works only in some shells like bash or korn. See for example mywiki.wooledge.org/BashFAQ/031 Jul 21, 2016 at 13:58

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .