Search code examples
regexbashshellls

How to expand tilde (~) in path


I have a shell script that get's directory path from user, but i need to check directory empty or not. In case user put his home path with ~ instead of absolute path, so I can't check it with ls

  echo "Specify your project root directory. For example: ~/Base/project1"

  read directory

  if [ ! -z "$directory" ]
  then

    if [ "$(ls -A "$directory")" ]
    then
      echo Directory $directory is not empty
    else
      echo The directory $directory is empty '(or non-existent)'
    fi
    directory="$directory"

  else

    echo "No root directory specified. Exiting.."
    exit;

  fi

I'm getting error: ls cannot read path with ~ , how to expand it before checking directory is empty?


Solution

  • Original answer

    Try this:

    eval directory="$directory"
    

    Since nothing can interpret the special shell characters better than the shell itself, it is a good idea to ask the shell to evaluate the expression for us. And eval is just the command that evaluates shell expressions.

    Alternative #1: program in C

    However, eval is unsafe, as it has been mentioned many times, - it may execute malicious code, or cause unwanted effects. Then, for a POSIX environment, you can write a simple program in C:

    tildeexp.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <wordexp.h>
    
    int
    main(int argc, char **argv)
    {
      wordexp_t p;
      int rc;
    
      rc = wordexp(argv[1], &p, 0);
      if (rc) {
        fprintf(stderr, "Failed to expand %s: %d\n",
            argv[1], rc);
      } else {
        printf("%s\n", p.we_wordc ? p.we_wordv[0] : "");
      }
      wordfree(&p);
    
      return (rc ? 1 : 0);
    }
    

    Compiling

    gcc -Wall -g -O2 -o tildeexp tildeexp.c
    

    Usage

    directory=$(/path/to/tildeexp "$directory")
    if [ $? -eq 0 ]; then
      # success
    else
      # failed to expand
    fi
    

    Alternative #2: Perl's glob

    directory="${directory//$"'"/$"\\'"}"
    directory=$(perl -e "print glob('$directory')")