5

I was trying to execute a program which will create a directory on the basis of a complete path provided to it from the prompt and, if the directory already exists it will return an error (for "directory already exists") and ask again for the name in a recursive function.

Here it is what I tried: let us say a file, test1 in it:

#!/bin/bash
echo "enter the directory name"
read ab
check(){
if (( echo `mkdir $ab` 2>/dev/null )); then
  echo "directory created "
  echo `ls -ld $ab`
  exit
else
  echo "try again "
  echo "enter new value for directory:"
  read ab
  check
fi
}
check

The problem here is if the directory exists then the program works fine but if it does not exist then it creates it but then goes to the else part of the program.

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
AshwaraS
  • 71
  • 1
  • 2
  • 4

4 Answers4

3

The echo always succeeds. Do without it and the subshell:

#!/bin/bash
echo "enter the directory name"
read ab
check(){
    if mkdir "$ab" 2>/dev/null; then
      echo "directory created "
      ls -ld "$ab"
      exit
    else
      echo "try again "
      echo "enter new value for directory: "
      read ab
      check
    fi
}
check
janos
  • 11,341
2
(( echo `mkdir $ab` 2>/dev/null ))
bash: ((: echo  2>/dev/null : syntax error in expression (error token is "2>/dev/null ")

Double parentheses surround arithmetic expressions. That command that doesn't do anything close to what you intended. mkdir $ab doesn't write anything to standard output, so `mkdir $ab` is an empty string, so the content of the arithmetic expression is echo 2>/dev/null. The > sign is the “greater than” operator here, and echo is a variable name. The arithmetic expression is syntactically incorrect (you can't have a variable followed by a literal integer). Since the command is syntactically incorrect, it returns an error status, and the else branch is taken.

To test the return status of a command, just write that command.

if mkdir -- "$ab" 2>/dev/null

Additional tips:

  • It's a bad idea to hide the errors from a command. The user needs to know if the error is permission denied, I/O error, etc. To create a directory if it isn't there and succeed if the directory already exists, use mkdir -p -- "$ab".
  • Always use double quotes around variable substitutions.
  • If the value of ab begins with a dash, it'll be interpreted as an option. Put -- first to mark the end of options.
1
tries=0
while [ "$((tries+=1))" -le 5 ]    || ! break
      printf 'enter dirname: > '
      IFS=   read -r dir    && 
      if   ! mkdir -- "$dir"
      then   echo try again
      else ! echo Success\!
      fi  
do :; done

I'm not sure why you want to negate the exit statuses like that, but I think the above should get something like the inversion you're looking for - and it should quit after a limited number of $tries.

If I run it...?

enter dirname: > .
mkdir: cannot create directory ‘.’: File exists
try again
enter dirname: > .
mkdir: cannot create directory ‘.’: File exists
try again
enter dirname: > .
mkdir: cannot create directory ‘.’: File exists
try again
enter dirname: > .
mkdir: cannot create directory ‘.’: File exists
try again
enter dirname: > .
mkdir: cannot create directory ‘.’: File exists
try again

And... again...

enter dirname: > doesntexist
Success!
mikeserv
  • 58,310
0

This idea will make things slightly more complex, but I propose the more proper way of doing this is to utilize proper tests in your script. Something to the effect of:

#!/bin/bash
if [[ -n $1 ]]; then
  dirname=$1
fi

if [[ -z $dirname ]]; then
  echo "Enter directory name."
  read dirname
fi

check() {
  if [[ -d "$dirname" ]]; then
    echo "Directory already exists."
    echo "Enter new directory name."
    read dirname
    check
  elif [[ -e "$dirname" ]]; then
    echo "$dirname already exists, but is not a directory."
    echo "Enter new directory name."
    read dirname
    check
  else
    if mkdir -p -- "$dirname"; then
      echo "Directory created"
      ls -ld "$dirname"
    fi
    exit
  fi
}
check

This would preserve the error messaging from the call you make (mkdir) as well as perform some useful tests to give feedback on why an attempt failed. Additionally, you can optionally pass the desired directory name as a command line argument, and it will only ask you to input it on the second attempt.

magamo
  • 1
  • In fact there is a whole proper command construct called case for this - all of those layered ifs might be confusing. – mikeserv Dec 26 '14 at 02:22