12

What I'm trying to do

I've created a shell script that I've added to my $PATH that will download and get everything setup for a new Laravel project. I would like the script to end by changing my terminal directory into the new project folder.

From what I understand right now currently it's only changing the directory of the sub shell where the script is actually running. I can't seem to figure out how to do this. Any help is appreciated. Thank you!

#! /usr/bin/env bash

echo -e '\033[1;30m=========================================='

## check for a directory
if test -z "$1"; then
  echo -e ' \033[0;31m✖ Please provide a directory name'
  exit
fi

## check if directory already exist
if [ ! -d $1 ]; then
  mkdir $1
else
  echo -e ' \033[0;31m✖ The '"$1"' directory already exists'
  exit
fi

# move to directory
cd $1

## Download Laravel
echo -e ' \033[0;32m+ \033[0mDownloading Laravel...'
curl -s -L https://github.com/laravel/laravel/zipball/master > laravel.zip

## Unzip, move, and clean up Laravel
echo -e ' \033[0;32m+ \033[0mUnzipping and cleaning up files...'
unzip -q laravel.zip
rm laravel.zip
cd *-laravel-*
mv * ..
cd ..
rm -R *-laravel-*

## Make the /storage directory writable
echo -e ' \033[0;32m+ \033[0mMaking /storage directory writable...'
chmod -R o+w storage

## Download and install the Generators
echo -e ' \033[0;32m+ \033[0mInstalling Generators...'
curl -s -L https://raw.github.com/JeffreyWay/Laravel-Generator/master/generate.php > application/tasks/generate.php

## Update the application key
echo -e ' \033[0;32m+ \033[0mUpdating Application Key...'
MD5=`date +”%N” | md5`
sed -ie 's/YourSecretKeyGoesHere!/'"$MD5"'/' application/config/application.php
rm application/config/application.phpe

## Create .gitignore and initial git if -git is passed
if [ "$2" == "-git" ]; then
  echo -e ' \033[0;32m+ \033[0mInitiating git...'
  touch .gitignore
  curl -s -L https://raw.github.com/gist/4223565/be9f8e85f74a92c95e615ad1649c8d773e908036/.gitignore > .gitignore

  # Create a local git repo
  git init --quiet
  git add * .gitignore
  git commit -m 'Initial commit.' --quiet
fi

echo -e '\033[1;30m=========================================='
echo -e ' \033[0;32m✔ Laravel Setup Complete\033[0m'

## Change parent shell directory to new directory
## Currently it's only changing in the sub shell
filepath=`pwd`
cd "$filepath"
michaelespinosa
  • 505
  • 2
  • 5
  • 15

5 Answers5

9

You can technically source your script to run it in your parent shell instead of spawning a subshell to run it. This way whatever changes you make to your current shell (including changing directories) persist.

source /path/to/my/script/script

or

. /path/to/my/script/script

But sourcing has its own dangers, use carefully.

(Peripherally related: how to use scripts to change directories)

sampson-chen
  • 45,805
  • 12
  • 84
  • 81
  • For some reason this doesn't seem to work for me. I've tried both ways. Once I source the script how do I call it? – michaelespinosa Dec 07 '12 at 00:12
  • @michaelespinosa sourcing the script IS calling it. If you'd like to make it into a callable command, wrap your entire script in a function (for example, `foo() {...script contents...}` and then source that instead; invoke the function on your command prompt to execute the instructions within. – sampson-chen Dec 07 '12 at 00:15
  • Ok, in that case, when I was sourcing the file it was crashing terminal on my mac. Interesting... – michaelespinosa Dec 07 '12 at 00:23
6

Use a shell function to front-end your script

setup () {
  # first, call your big script.
  # (It could be open-coded here but that might be a bit ugly.)

  # then finally...

  cd someplace
}

Put the shell function in a shell startup file.

DigitalRoss
  • 143,651
  • 25
  • 248
  • 329
  • This actually worked for me, thanks! There is a problem when the script calls 'exit' because of a duplication the terminal window crashes. – michaelespinosa Dec 07 '12 at 01:05
  • And for others reading this, shell functions can be passed arguments just like scripts. Inside the function, `$*, $@,` and `$1, $2 ...` all refer to the arguments passed to the function, i.e., `setup arg1 arg2`. – DigitalRoss Dec 07 '12 at 15:35
  • I could fix the crashes by wrapping the script in if statements instead of calling exit. Thanks @DigitalRoss – michaelespinosa Dec 07 '12 at 18:11
3

Child processes (including shells) cannot change current directory of parent process. Typical solution is using eval in the parent shell. In shell script echo commands you want to run by parent shell:

echo "cd $filepath"

In parent shell, you can kick the shell script with eval:

eval `sh foo.sh`

Note that all standard output will be executed as shell commands. Messages should output to standard error:

echo "Some messages" >&2
command ... >&2
yasu
  • 1,374
  • 8
  • 16
1

This can't be done. Use exec to open a new shell in the appropriate directory, replacing the script interpreter.

exec bash
Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
  • A little explanation of `exec` would improve this answer. – kojiro Dec 06 '12 at 21:48
  • I don't see how `exec` is relevant here, you are still in a subshell of your original shell. However, I would argue that this is extremely counterintuitive -- I usually expect a script to terminate, not to drop me in another shell. Repeated use of this script would start to accumulate subshells ... – Lars Noschinski Dec 06 '12 at 21:59
  • 1
    @cebewee, I thought @ignacio-vazquez-abrams meant you should `exec bash the_script`, which would replace the original shell with the executing script; however, among other things, that would also cause the shell to exit as soon as the script completed. Without an explanation, this answer is pretty much wrong. – kojiro Dec 07 '12 at 05:22
  • This is a helpful answer despite not being ideal. I'm sure it's good enough for some desperate souls out there. – Sridhar Sarnobat Mar 29 '21 at 21:35
1

I suppose one possibility would be to make sure that the only output of your script is the path name you want to end up in, and then do:

cd `/path/to/my/script`

There's no way your script can directly affect the environment (including it's current directory) of its parent shell, but this would request that the parent shell itself change directories based on the output of the script...

twalberg
  • 59,951
  • 11
  • 89
  • 84