1

Trying to make a bash script (on mac) that creates a folder then runs a bunch of scripts in that folder. I want to echo the absolute path to folder and prompt user to confirm before taking action.

The script takes a relative path as an argument, how do I convert to an absolute path before creating the folder?

!/bin/bash
if [[ $# -eq 0 ]] ; then
  echo 'Whoa! You dont want to do that! you need to tell me where to put it'
  exit 0
fi

ORG_DIR=$(pwd)
#here I want to get path before making directory, I've only figured out how to do after.
mkdir ../$1
cd ../$1
NEW_DIR=$(pwd)

echo "Running scripts in"
echo $NEW_DIR
read -p "Are you sure? (y/n) " -n 1 -r
if [[ ! $REPLY =~ ^[Yy]$ ]]
then
   # run a bunch of scripts
fi

How do I get the absolute path of NEW_DIR before making it?

Note: Platform is OSX, I don't need to support other 'nix variants.

EDIT: Sat, 29

I realized that in an effort to trim the question down to essential details only, I trimmed to much, my apologies.

This script exists in (for example sake)

/Documents/git/ProjectGenerator

I intend the script to generate a project in (or whatever path is entered)

/Documents/git/NewProject

It runs a combination of npm scripts, and copying files from

/Documents/git/ProjectGenerator

The rest of the script works fine now, however I recently accidentally hit enter on the wrong dir. Since this script is intended for my use only (and not sudo), I'm trying to add a sanity check, not a security check to the beginning of the script. Must type Y and enter after looking at the dir.

I'm trying to get an absolute path and what I'm getting is

/Documents/git/ProjectGenerator/../NewProject

I'm trying to get it to echo

/Documents/git/NewProject

prior to creating the directory. (sometimes the path is far more complex)

In node we have path.resolve(path) In php or c its realpath(path)

I cant seem to find an equivalent command in osx bash, is there one? or do I need to parse the string?

  • You might want to check the exit status of some of your commands. What happens when $1 is ../../../../../System or foo bar? – doneal24 Sep 27 '18 at 2:21
  • In this case, its not a distributed script, for my use only, so no trust issues. – Philippe Sep 29 '18 at 19:50
  • I intend the prompt to be a sanity check, not a security check. – Philippe Sep 29 '18 at 20:05
2

You want to change to the previous directory with .. and that's causing problems finding out the absolute path of your new directory (named $1 in your script, I'll call it $new_directory_name here) that will be ../$new_directory_name.

Before doing any cd or mkdir, I'd use the basename command to show the original directory's ($PWD's) absolute path, then append $new_directory_name to it, like this:

echo $(dirname $PWD)/$new_directory_name

(or replace the $(...) command substitution with backticks `...` (they display funny on stackexchange sometimes - see the Command Substitution section of man bash

I believe you could just use bash's Parameter Expansion (also in man bash) on $PWD instead of basename like this:

 echo ${PWD%/*}/$new_directory_name

Examples

$ new_directory_name=newdir
$ pwd
/tmp/testdir
$ echo ${PWD%/*}/$new_directory_name
/tmp/newdir
$ echo $(dirname $PWD)/$new_directory_name
/tmp/newdir

Like user912264 mentions, you might consider checking whether .. is a writable directory (with stat -c %a or %A), or if you're already in / then cd .. doesn't go anywhere new, or just watch for errors from mkdir, like

mkdir ... || { echo mkdir ERROR exiting; exit; }
  • Not quite sure how getting the basename helps me transform the path to absolute. $(pwd) already gives an absolute path to the current directory. I'm trying to avoid having to create a directory to get its absolute path. – Philippe Sep 29 '18 at 21:04
  • Do you have an example of a directory you're in and a new directory name that you're trying to create, where this fails? Ah wait, I do see a confusing problem with variable names in your script though, you're using $NEW_DIR after you've already created it and it's already got an absolute path; my $NEW_DIR will work with a folder name only, no path (I'll edit my answer to clarify, I'll rename it to $new_directory_name) – Xen2050 Oct 1 '18 at 6:49
1

From this comment on stack overflow https://stackoverflow.com/questions/284662/how-do-you-normalize-a-file-path-in-bash#comment81662652_284671

I came to the conclusion coreutils (which I already had installed) has the greadlink command which has the functionality I need.

NEW_DIR=$(greadlink -f ../$1)

EDIT 1:

#!/bin/bash
if [[ $# -eq 0 ]] ; then
  #simple check to ensure enter was not accidently pressed without directory specified
  echo 'Whoa! You dont want to do that! you need to tell me where to put it';
  exit 0
fi

ORG_DIR=$(pwd)
#here I want to get path before making directory, I've only figured out how to do after.
NEW_DIR=$(greadlink -f ../$1)

echo "Running scripts in"
echo $NEW_DIR
read -p "Are you sure? (y/n) " -n 1 -r
if [[ $REPLY =~ ^[Yy]$ ]]
then

  cp -r $ORG_DIR/skeleton $NEW_DIR

  cd $NEW_DIR

  #init the project with default answers.
  yarn init -y

  #add dev scripts
  yarn add --dev webpack webpack-cli babel-loader @babel/preset-react @babel/core @babel/preset-env webpack-dev-server css-loader sass-loader node-sass style-loader file-loader url-loader redux-devtools eslint eslint-plugin-react babel-eslint

  #add production scripts
  yarn add react react-dom react-hot-loader react-redux redux redux-saga redux-socket.io socket.io

fi
  • Although this answers the question for me, I'm leaving it open hoping for a native solution (for educational reasons), if someone has one, I'll accept that answer. – Philippe Sep 29 '18 at 21:51
  • 1
    FYI, greadlink doesn't appear to be in a standard Debian / coreutils install, but readlink is, and seems to take about as much time to run as dirname, while bash's parameter expansion (echo ${PWD%/*}/$new_directory_name) doesn't register anything with time (0m0.000s), just in case someone's planning on running the commands A LOT – Xen2050 Oct 1 '18 at 7:05
  • 1
    Interesting, didn't know osx was that different. I believe the coreutils original source is GNU (interesting brief history), and the "big" (or DIY) distributions like Debian create their packages from there, trickling down to the derivative distributions. I'll bet the osx version is from GNU too, but I'm not sure. Anyway, readlink works too, so upvotes all around ;-) – Xen2050 Oct 2 '18 at 22:15
  • 1
    @Xen2050 OSX itself is a branch of Unix known as Darwin, I believe they branched in the late 90's, since then they have evolved in different directions. – Philippe Oct 2 '18 at 22:47
  • 1
    I do remember reading something similar somewhere, things get confusing with OS "family histories," like the Linux Distribution Timeline image. I think BSD is involved somehow too - found a Unix history-simple image with macOS under Wikipedia's macOS history (guess they're calling it just "macOS" now) – Xen2050 Oct 2 '18 at 23:07

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.