6

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?

  • 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 '16 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. – pabouk Jul 21 '16 at 13:50
13

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  
7

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.

  • 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. – Luciano Andress Martini Jul 20 '16 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 '16 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. – Luciano Andress Martini Jul 20 '16 at 18:50
  • 1
    Well I learned something new! I never revised my view of [ since 1999, apparently. – Satya Mishra Jul 20 '16 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 – pabouk Jul 21 '16 at 13:58

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.