0

I have a bash script I am trying to run through directories to the end of the line, for example if I have 4 directories in a row it will go down /d1/d2/d3/d4 until it finds files or other directories. If d3 has a file, it will stop there. I was doing this by counting the lines ls prints to a file and if there's 1 directory use that name in a cd command. My file is:

`

#!/bin/bash


COUNTFILE="/home/username/fake.txt"

ITEMCOUNT=$(ls | wc -l)
echo "ITEMCOUNT" $ITEMCOUNT

echo $*

ONE="1"
echo "one" $ONE

if [["$ITEMCOUNT" -eq "$ONE"]]; 
then
  DIRCOUNT=$(find . -maxdepth 1 -type d | wc -l)
  echo "dircount" $DIRCOUNT
else
  DIRCOUNT="0"
fi


if [$DIRCOUNT == "1"]; then
  ls > $COUNTFILE
  PATH=$(head -1 $COUNTFILE)
  cd ./$PATH
fi

`

As is I get

pipetester.sh: line 15: [[1: command not found
pipetester.sh: line 2

4: [0: command not found

I checked syntax for 2 hours, but it seems to be complaining about my "if" lines, why?

5
  • BTW, using a math context -- as in if (( DIRCOUNT == 1 )) -- may be more readable. Also, using all-caps variable names is bad form for variables internal to your script; by convention, all-caps names are reserved for environment variables and shell builtins to avoid namespace conflicts. Commented Mar 12, 2015 at 22:53
  • On a different point, shellcheck.net would have caught this bug. Might save a few hours next time. :) Commented Mar 12, 2015 at 22:54
  • Please note that it is deemed courteous to use the name that the user chooses for themselves on SO, so 'Duffman' as a way of addressing Charles Duffy is inappropriate. You can use @CharlesDuffy as a way of addressing him, where you type the @ and the C and can then choose from a list of candidates (or type the name manually). Commented Mar 13, 2015 at 3:04
  • @JonathanLeffler, no worries. (I was actually wondering, for a moment, if this was someone who knew me from the mid-90s, when this was among my nicknames... though not one I chose or would choose myself). Commented Mar 13, 2015 at 3:22
  • @JonathanLeffler Ok thanks...it was actually the cool character on The Simpsons Commented Mar 13, 2015 at 13:06

2 Answers 2

5

Put spaces around command names like [[ and [.

For example:

if [[ "$ITEMCOUNT" -eq "$ONE" ]]
then

or, if you like semicolons:

if [[ "$ITEMCOUNT" -eq "$ONE" ]]; then

And:

if [ $DIRCOUNT == "1" ]; then

or (better use of quotes):

if [ "$DIRCOUNT" == "1" ]; then  # Or just 1 (no quotes around it)

Because these are commands, you need spaces around the components of the expression too (as you have them already). Don't skimp on spaces in shell scripts (but also don't use them where they are not allowed, such as around the = in a variable assignment).

Note that both the [[ command and the == operator for [ are Bash extensions compared to the POSIX shell.

Sign up to request clarification or add additional context in comments.

6 Comments

In the last example, $DIRCOUNT could stand to be quoted, whereas "1" need not be.
@CharlesDuffy: true. Updated.
I ran a test from a post about testing type, and it said that $DIRCOUNT wasn't an int, why can 1 be 1 or "1"
@CodyChilders, because [ is a command, and like every other command, its arguments are in string form when they're actually passed into it. That there exist variables that are only capable of storing integers in shell is somewhat academic -- when those variables are expanded, the result is a string.
@CodyChilders, ...the other thing to keep in mind is that "$DIRCOUNT" doesn't expand to "1"; it expands to 1. The quotes modify the expansion itself to prevent string-splitting and glob expansion behaviors; they aren't copied into the output. (This means that if your IFS variable contained 1, then $DIRCOUNT would expand to nothing at all -- because it would contain only a delimiter character which string-splitting would eliminate -- whereas "$DIRCOUNT" would still expand to 1).
|
1

You need to put spaces around the [[ and ]] tokens, [[ is an actual command:

if [[ "$ITEMCOUNT" -eq "$ONE" ]];

The way you have it now is little different to expecting ls-al (without a space preceding the -) to give you a full directory listing.

The complaint about the [[1 command is because $ITEMCOUNT is set to 1 and is being combined with the [[ text:

pax$ xyzzy=1

pax$ if [[$xyzzy == 1]]; then echo yes; fi
-bash: [[1: command not found

pax$ if [[ $xyzzy == 1 ]]; then echo yes; fi
yes

You also need to do this for [ and ] as well, for the same reason.

2 Comments

What is the difference between [[ ]] and [ ] please? [ ] isn't a command?
@CodyChilders, [ is indeed also a command -- in fact, it's much more a conventional command than [[ is, as the former is a builtin that follows normal parsing and syntax rules, whereas the [[ is syntax, and changes the way its contents are parsed (which is why, for instance, double-quotes have a meaning different from their usual one within it).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.