Source command in bash script - bash

I am trying to put a source command in a bash script so that I can quickly set up and use a virtual environment when writing django websites.
I tried the following without much success as my path was not prefixed with the (path) like it does when I simply enter it at the prompt.
#!/bin/bash
current=$(pwd | cut -d'/' -f5)
source ~/Documents/virtual-env/$current/bin/activate
Can anybody help and let me know what I am overlooking?
EDIT:
pwd is "example" and the source is:
"~/Documents/virtual-env/example/bin/activate".
After some research I think I need to use something like:
"source ./script"
(not working) as I think the environment is created but not esculated to its parent enviroment which I believe is not possible now.

#!/bin/bash
current=$(basename $(pwd))
source ~/Documents/virtual-env/$current/bin/activate
exec bash # Run new interactive shell in the new environment
But I recommend to try virtualenvwarpper instead.

Related

How to set up a running environment on Ubuntu?

I want to customize a command to set up running environment, but I'm having some issue here. For example, I can run:
envsetup
and it will run the following script to help set up the environment:
cd /opt/dir/set_up | source environment
I have tried to add the following code to my $HOME .bashrc file, but it's not working (Maybe I should add it to the .bashrc in my root dir?):
alias envsetup = 'cd /opt/dir/set_up | source environment'
Could anyone let me know what might be wrong here please?
A couple of things:
The cd command changes directories and doesn't output anything to
standard output (stdout). So there's no point in piping its output to another command with |. If you want to execute two commands in sequence, you can separate with ;.
When defining an alias you can't be too generous
with spaces.
Here's an option, then, to do what I think you want:
alias envsetup='cd /opt/dir/set_up ; source environment'
Per additional desire expressed in the comment, if you want to come back to the original directory, you can do it this way:
alias envsetup='(cd /opt/dir/set_up ; source environment)'
This runs the commands in a subshell so your current shell setup is unchanged, including the current working directory.
Note that since this runs in a subshell, if source is intended to change the environment variables in a persistent way, then this will not work. You can, alternatively, try something like this:
alias envsetup='p=$(pwd) ; cd /opt/dir/set_up ; source environment ; cd $p'
This will run in the same shell. You can choose whatever name you wish for p.

running a shell script from another script

I have a script in unix that looks like this:
#!/bin/bash
gcc -osign sign.c
./sign < /usr/share/dict/words | sort | squash > out
Whenever I try to run this script it gives me an error saying that squash is not a valid command. squash is a shell script stored in the same directory as this script and looks like this:
#!/bin/bash
awk -f squash.awk
I have execute permissions set correctly but for some reason it doesn't run. Is there something else I have to do to make it able to run like shown? I am rather new to scripting so any help would be greatly appreciated!
As mentioned in #Biffen's comment, unless . is in your $PATH variable, you need to specify ./squash for the same reason you need to specify ./sign.
When parsing a bare word on the command line, bash checks all the directories listed in $PATH to see if said word is an executable file living inside any of them. Unless . is in $PATH, bash won't find squash.
To avoid this problem, you can tell bash not to go looking for squash by giving bash the complete path to it, namely ./squash.

shebang script interpreter from shell variable

I have a number of scripts which need to specify the python binary which runs them:
#! /home/nargle/python/bin/python2.6
I need to adapt these scripts to work at two different sites. Lots of tools are installed in different places, so at new site 2 the script needs to start with:
#! /user/nargle/python/bin/python2.6
..
I want to replace directly-quoted paths with environment variables which are set differently for each site. What I would like is for this to work:
#! $MY_PYTHON_PATH
but it doesn't! I am slightly hazy on where to research this. Is it the executing shell (be it bash, csh or whatever) which detects the '#!' at the start of a script (be it bash, python or whatever) and fires up the interpreter/shell to run it?
I feel that there must be some way to do this. Please advise!
Oh yes, there is one more constraint: we cannot use the path for this. This may seem like a stupid restriction but this is for a large environment with many users
The environment is RHEL 5.7.
EDIT It has been suggested to use a shell script and that is the current plan: it works fine:
$MY_PYTHON_PATH some_script file.py $#
The problem is really that we have lots of people using the python files, and lots of automated tests which need to changed. If it has to be done it has to be done but I if possible I want to minimise the impact of a change of working practice for scores of people.
EDIT It would also be possible to have a link in a location which is the same on both systems, and which links to the real binary in a different target on each system. This is quite feasible but seems kind of messy: we use the linux 'modules' package to setup environment variables for many tools and it would be nice if we could take the python path from our modulefiles.
EDIT It isn't the answer but this feels like the kind of evil hack I was looking for:
http://docs.nscl.msu.edu/daq/bluebook/html/x3237.html
.. see "Example 4-2. #! lines for bash and for tclsh"
EDIT I hoped this might work but it didn't:
!# /usr/bin/env PATH=$PATH:$MY_PYTHON_PATH python2.6
The common solution is to change the shebang to
#!/usr/bin/env python2.6
Then, just arrange your $PATH to point to the right python2.6 on each machine.
Write a wrapper shell script. If you have script.py, write a script.py.sh with the following content:
#!/bin/bash
PYTHON_SCRIPT=$( echo "$0" | sed -e 's/\.sh$//' )
exec $MY_PYTHON_PATH $PYTHON_SCRIPT "$#"
Disclaimer: This isn't tested, just wrote it off the top of my head.
Now just set up your MY_PYTHON_PATH on each machine, and call script.py.sh instead of script.py.
Summary This solution is only second-best, since it requires a lot of script calls to be changed from script.py to script.py.sh, something that should be avoided if at all possible.
Alternative
Use env to call a python-finder script, which just calls the python binary contained in $MY_PYTHON_PATH. The python-finder script has to be in the same location on both machines, use symlinks if necessary.
#!/usr/bin/env /usr/local/bin/python-finder.sh
The contents of python-finder.sh:
#!/bin/bash
exec $MY_PYTHON_PATH "$#"
This works because for interpreter scripts (those starting with a shebang) execve calls the interpreter and passes the filename to env, which in turn passes it on to the command it calls.
I was being silly: using variable expansion with env does work.
#! /usr/bin/env PATH="$PATH:$MY_PYTHON_PATH" python2.6
We can do:
#!/bin/bash
"exec" "python" "$0"
print "Hello World"
from http://rosettacode.org/wiki/Multiline_shebang#Python

Is it possible to specify the bash prompt using a command-line option?

I use vim a lot and often find it useful to drop into the command line using !bash.
However, I need to type exit to return to vim and sometimes I'm not sure whether I'm in a subshell or whether that will close my session.
What I'd really like to do is type something like !bash -prompt "subshell" so that I get something like this:
subshell$ <commands go here>
Is this possible?
The most direct way to do this is to set the PS1 environment variable within vim:
:let $PS1="subshell$ "
And start your sub-shells using the command :shell instead of :!bash.
Using the $ sign with let modifies an environment variable. Add this to your .vimrc to persist the setting.
Alternately, using :shell you can specify a more specific command, including arguments, using the shell option, see help shell and help 'shell'.
So:
:set shell=bash\ --rcfile\ ~/.vimbashrc
In .vimbashrc add PS1="subshell ", and invoke the sub-shells using :shell instead of !bash. Add this to your .vimrc to persist the setting.
So you have two options:
Add let $PS1="subshell " to your .vimrc, and start sub-shells using :shell instead of :!bash.
Make a custom rc file for your vim sub-shells, add your specific PS1="subshell " to it, and modify the shell option in your .vimrc: set shell=bash\ --rcfile\ ~/.vimbashrc.
Finally, if you must use :!bash to start the sub-shells there are a couple of more options. Note that you can also pass a more specific command line using !, e.g.:
:PS1="subshell$ " bash should work.
:!bash\ --rcfile\ ~/.vimbashrc, and set PS1 in .vimbashrc as above
But you'll need to type these every time, or define a mapping for it.
Use shell variable $SHLVL seems to be another option here. Add $SHLVL in your $PS1:
export PS1="$PS1 $SHLVL"
so your prompt looks like this:
[tim#RackAblade47 ~]$ 2
when you start shell from VIM, $SHLVL will increase:
[tim#RackAblade47 ~]$ 4
Yes - you can change the prompt inside the shell before running your commands
PS1="subshell"
checkout this guide for all the options http://www.linuxselfhelp.com/howtos/Bash-Prompt/Bash-Prompt-HOWTO-2.html
If you really must do it via the bash command you can use '--rcfile' to specify an RC file that runs the PS1 command for you (you usually put the PS1= line your .bashrc to customize the prompt at login)
To answer your original question, you can say inside Vim:
:!VIMPROMPT="(vim) " bash
and change your prompt (in your .bashrc, presumably) from something like
PS1='\u#\h:\w\$ '
to
PS1='$VIMPROMPT\u#\h:\w\$ '
this will change your prompt from
me#host:~$
to
(vim) me#host:~$
if run inside Vim.
I'm personally using
case $(ps $PPID) in *vim|*bash)
PS1="$(ps $PPID | awk '{print $NF}' | sed 1d) $PS1" ;;
esac
in my prompt script that's sourced by my .bashrc, taken from triplee's comment.
I have been able to change the prompt for a vim subshell process by checking for the MYVIMRC variable which is exported inside vim, and will then update PS1 accordingly. I updated my .bashrc file with the following.
PS1='\$ '
# when in vim subshell change PS1 for clarity
if [[ $MYVIMRC ]]; then PS1='>> '; fi;
Put this in your .bashrc after any existing PS1= statements.
if ps | grep -q vim; then
export PS1="[VIM]$PS1"
fi
Tested on Ubuntu.
You can send it to the background with CTRL+Z and then bring it back with the fg command. With jobs you see all the jobs you have stopped.
This was you can have multiple instances of vim in parallel and chose which one you want to bring back. If there's no running you will just get a no current job error and that's it.
This doesn't specifically answer your question, but addresses the problem underneath it.

In bash2, how do I find the name of a script being sourced?

Here's my situation:
I have multiple versions of a script in source code control where the name differs by a path name component (ex: scc/project/1.0/script and scc/project/1.1/script). In another directory, there is a symlink to one of these scripts. The symlink name is not related to the script name, and in some cases may change periodically. That symlink, in turn, is sourced by bash using the '.' command.
What I need to know: how do I determine the directory of the referenced script, on a 10 year-old system with Bash 2 and Perl 5.5? For various reasons, the system must be used, and it cannot be upgraded.
In Bash 3 or above, I use this:
dir=`perl -MCwd=realpath -MFile::Basename 'print dirname(realpath($ARGV[0]))' ${BASH_SOURCE[0]} $0`
Apologies for the Perl one-liner - this was originally a pure-Perl project with a very small amount of shell script glue.
I've been able to work around the fact that the ancient Perl I am using doesn't export "realpath" from Cwd, but unfortunately, Bash 2.03.01 doesn't provide BASH_SOURCE, or anything like it that I've been able to find. As a workaround, I'm providing the path information in a text file that I change manually when I switch branches, but I'd really like to make this figure out which branch I'm using on its own.
Update:
I apologize - apparently, the question as asked is not clear. I don't know in every case what the name of the symlink will be - that's what I'm trying to find out at run time. The script is occasionally executed via the symlink directly, but most often the link is the argument to a "." command running in another script.
Also, $0 is not set appropriately when the script is sourced via ".", which is the entire problem I'm trying to solve. I apologize for bluntness, but no solution that depends entirely upon $0 being set is correct. In the Perl one-liner, I use both BASH_SOURCE and $0 (BASH_SOURCE is only set when the script is sourced via ".", so the one-liner only uses $0 when it's not sourced).
Try using $0 instead of ${BASH_SOURCE[0]}. (No promises; I don't have a bash 2 around.)
$0 has the name of the program/script you are executing.
Is stat ok? something like
stat -c %N $file
bash's cd and pwd builtins have a -P option to resolve symlinks, so:
dir=$(cd -P -- "$(dirname -- "$0")" && pwd -P)
works with bash 2.03
I managed to get information about the porcess sourcing my script using this command:
ps -ef | grep $$
This is not perfect but tells your which is the to process invoking your script. It migth be possible with some formating to determine the exact source.

Resources