Running executables without ./ or bash or source - bash

I am learning the basics of bash and linux. To execute a script, I could type...
bash script1
or
source script1
or
./script1
The first two will run without chmod u+x and the last one requires it.
From my understanding, bash tries to run things in a subshell so it doesn't mess things up. When I add bash before the filename, it's executed in a subshell. source is just a way of telling the computer to run it in the current shell. I'm not sure why these don't require the execute permission though.
./ is pretty straightforward. However, I've seen people run scripts without the ./. One told me I could do this by doing something with PATH. I completely don't understand this PATH thing.
Can someone explain in the easiest way possible?

On
bash script1
you are executing bash (the one that needs execution permission) to read and process script1 (which needs read permission).
On
source script1
you are telling the current bash to read the file and process it as if it were typed on the current shell, so the current bash reads the script (read permission) and executes every line.
Finally, on
./script1
you are telling bash to try to run a file called ./script1, so it checks if it is executable (execute permission on ./script1) and passes this file to the kernel to be executed. The kernel opens the file and acts as needed (if it have a shebang line, it uses whatever is given, if it finds it is an ELF object, it prepares the binary in memory...).
Regarding PATH, check some documentation and come back with specific doubts, if any.

PATH is environmental variable. It is a list containing all directories that will be searched when you issue a command. So if your PATH is defined as PATH=/bin:/usr/bin these two dirs will be searched, if you redefine it as export PATH=./:$PATH it will also add current directory to search list.

Related

How to run shell script by including "cd" command in ubuntu?

I am trying to execute a shell script for automating the process rather than manually running the python script. But i am getting the error folder not found.
cd /home/gaurav/AndroPyTool
export ANDROID_HOME=$HOME/android-sdk-linux/
export PATH=$PATH:$ANDROID_HOME/tools
export PATH=$PATH:$ANDROID_HOME/platform-tools
source ~/.bashrc
source droidbox_env/bin/activate
alias mycd='cd /home/gaurav/AndroPyTool/test'
mycd
pwd
python androPyTool.py -all -csv EXPORTCSV.csv -s mycd
>>>> AndroPyTool -- STEP 1: Filtering apks
Folder not found!
This is the error i am getting because the script is not able to find the path that i have provided above.
The part after "-s" in the code represents the folder path where the file stored.
The issue here is that you are not passing the path to the python program. The python program is not aware of bash aliases and bash will only expand aliases when it is interpreting the token as a command.
When bash reads python androPyTool.py -all -csv EXPORTCSV.csv -s mycd It interprets python as the command and all other space separated tokens are arguments that will be passed into python. Python then invokes androPyTool.py and passes the subsequent arguments to that script. So the program is receiving literally mycd as the argument for -s.
Moreover, even if mycd is expanded, it wouldn't be the correct argument for -s. androPyTool.py is expecting just the /path/to/apks, not cd /path/to/apks/.
I don't really think that using the alias in this script makes much sense. It actually makes the script harder to read and understand. If you want to wrap a command, I recommend defining a function, and occasionally you can use variable expansion (but that mixes code and data which can lead to issues). EDIT: As has been pointed out in the comments, aliases are disabled for scripts.
Finally there are some other suspicious issues with your script. Mainly, why are you sourcing .bashrc? If this script is run by you in your user's environment, .bashrc will already be sourced and there is no need to re-source it. On the other hand, if this is not intended to be run in your environment, and there is something in the .bashrc file that you need in your script, I recommend pulling just that out and nothing else.
But the most immediate issue that I can see is that sourcing .bashrc after you modify path runs the risk of overwriting the changes to PATH you just made. Depending on the contents of the .bashrc file, sourcing it may not be idempotent, meaning that running it more than once could have side effects. Finally, anything could get thrown in that .bashrc file down the road since that's what its for. So now your script may depend on something that likely will be changing. This opens up the possibility that bugs will creep in to your script unexpectedly.

getting permission to execute a bash script

im trying to get my server to execute a simple bash script:
#!/bin/bash
echo Hello World
After saving this to /var/www/script (im saving it to the web directory for no reason in particular) i try and execute it with
exec /var/www/script
This fails returning i don't have permission to execute it, sudo exec isn't a thing so i do sudo -i then run exec /var/www/script as root and i still have permission denied. I fairly uncertain why executing it as root doesn't work. Im wondering if i'm
A) using the wrong command to execute a bash script
B) have incorrect formatting in the script
C) shouldn't have saved it to /var/www/
D) done some other thing that i'm not even aware of.
Im running ubuntu server 16.04 if that helps.
File Permissions
First, make sure that you have the correct file permissions:
chmod +x /var/www/script_name #Gives the current user execute permissions
Executing Your Bash Script
In order to execute your bash script, the easiest option is to just simply call it (without any additional commands) by typing in the relative path to the script:
/var/www/script_name
There are other options for explicitly executing your script from the shell (in your case, use the bash shell to execute your script as a bash script). From TLDP documentation...
A script can also explicitly be executed by a given shell, but generally we only do this if we want to obtain special behavior, such as checking if the script works with another shell or printing traces for debugging:
rbash script_name.sh # Execute using the restricted bash shell
sh script_name.sh # Execute using the sh shell
bash -x script_name.sh # Execute using the bash shell
A Note on File Extensions: "Shebang" line > File extension
It is not an advised practice to use file extensions with your scripts, especially if you think your code may evolve beyond its current functionality.
Just in case you were wondering if the file extension may be your problem... it is not. It is important that you know that the file extension of a script isn't necessary at all. What matter is what you put in the "shebang" line:
To use the sh shell:
#!/bin/sh
To use the bash shell:
#!/bin/bash
It won't matter what file extension you use - the "shebang" line indicates what shell will be used to execute the script. You could save a script with the "shebang" of #!/bin/bash as script_name.py, but it would remain a bash script. If you attempt to execute it, ./script_name.py, it would be executed as a bash script.
As #Arjan mentioned in the comments, using file extensions for your script could lead to unnecessary complications if you decide to change the implementation of your project (i.e., a different shell / language):
I could decide later to shift my project to sh, python, perl, C, etc. Perhaps because I want to add functionality. Perhaps because I want to make it portable to a system without bash. It would be much more difficult if I used the .sh file extension, since then I'd need to change all my references to the script just because I changed its implementation.
You have two choices:
Run it as an argument to bash:
bash /var/www/script
Alternatively, set the execute bit:
chmod +x /var/www/script
And, now you can execute it directly:
/var/www/script

How can I store and execute the command "export PATH=$PREFIX/bin" from a script?

I would like to write a script that has several commands of the kind
> export PATH=$PREFIX/bin
Where
> $PREFIX = /home/usr
or something else. Instead of typing it into the the Shell (/bin/bash) I would run the script to execute the commands.
Tried it with sh and then with a .py script having the line,
> commands.getstatusoutput('export PATH=$PREFIX/bin')
but these result into the error "bad variable name".
Would be thankful for some ideas!
If you need to adjust PATH (or any other environment variable) via a script after your .profile and equivalents have been run, you need to 'dot' or 'source' the file containing the script:
. file_setting_path
source file_setting_path
The . notation applies to all Bourne shell derivatives, and is standardized by POSIX. The source notation is used in C shell and has infected Bash completely unnecessarily.
Note that the file (file_setting_path) can be specified as a pathname, or if it lives in a directory listed on $PATH, it will be found. It only needs to be readable; it does not have to be executable.
The way the dot command works is that it reads the named file as part of the current shell environment, rather than executing it in a sub-shell like a normal script would be executed. Normally, the sub-shell sets its environment happily, but that doesn't affect the calling script.
The bad variable name is probably just a complaint that $PREFIX is undefined.
Usually a setting of PATH would look something like
export PATH=$PATH:/new/path/to/programs
so that you retain the old PATH but add something onto the end.
You are best off putting such things in your .bashrc so that they get run every time you log in.

"Command not found" inside shell script

I have a shell script on a mac (OSX 10.9) named msii810161816_TMP_CMD with the following content.
matlab
When I execute it, I get
./msii810161816_TMP_CMD: line 1: matlab: command not found
However, when I type matlab into the shell directly it starts as normal. How can it be that the same command works inside the shell but not inside a shell script? I copy-pasted the command directly from the script into the shell and it worked ...
PS: When I replace the content of the script with
echo matlab
I get the desired result, so I can definitely execute the shell script (I use ./msii810161816_TMP_CMD)
Thanks guys!
By default, aliases are not expanded in non-interactive shells, which is what shell scripts are. Aliases are intended to be used by a person at the keyboard as a typing aid.
If your goal is to not have to type the full path to matlab, instead of creating an alias you should modify your $PATH. Add /Applications/MATLAB_R2014a.app/bin to your $PATH environment variable and then both you and your shell scripts will be able to simply say
matlab
This is because, as commenters have stated, the PATH variable inside of the shell executing the script does not include the directory containing the matlab executable.
When a command name is used, like "matlab", your shell looks at every directory in the PATH in order, searching for one containing an executable file with the name "matlab".
Without going into too much detail, the PATH is determined by the shell being invoked.
When you execute bash, it combines a global setting for basic directories that must be in the PATH with any settings in your ~/.bashrc which alter the PATH.
Most likely, you are not running your script in a shell where the PATH includes matlab's directory.
To verify this, you can take the following steps:
Run which matlab. This will show you the path to the matlab executable.
Run echo "$PATH". This will show you your current PATH settings. Note that the directory from which matlab is included in the colon-separated list.
Add a line to the beginning of your script that does echo "$PATH". Note that the directory from which matlab is not included.
To resolve this, ensure that your script is executed in a shell that has the needed directory in the PATH.
You can do this a few ways, but the two most highly recommended ones would be
Add a shebang line to the start of your script. Assuming that you want to run it with bash, do #!/bin/bash or whatever the path to your bash interpreter is.
The shebang line is not actually fully standardized by POSIX, so BSD-derived systems like OSX will happily handle multiple arguments to the shebanged executable, while Linux systems pass at most one argument.
In spite of this, the shebang is an easy and simple way to document what should be used to execute the script, so it's a good solution.
Explicitly invoke your script with a shell as its interpreter, as in bash myscript.sh or tcsh myscript.sh or even sh myscript.sh
This is not incompatible with using a shebang line, and using both is a common practice.
I believe that the default shell on OSX is always bash, so you should start by trying with that.
If these instructions don't help, then you'll have to dig deeper to find out why or how the PATH is being altered between the calling context and the script's internal context.
Ultimately, this is almost certainly the source of your issue.

Why does this script work in the current directory but fail when placed in the path?

I wish to replace my failing memory with a very small shell script.
#!/bin/sh
if ! [ –a $1.sav ]; then
mv $1 $1.sav
cp $1.sav $1
fi
nano $1
is intended to save the original version of a script. If the original has been preserved before, it skips the move-and-copy-back (and I use move-and-copy-back to preserve the original timestamp).
This works as intended if, after I make it executable with chmod I launch it from within the directory where I am editing, e.g. with
./safe.sh filename
However, when I move it into /usr/bin and then I try to run it in a different directory (without the leading ./) it fails with:
*-bash: /usr/bin/safe.sh: /bin/sh: bad interpreter: Text file busy*
My question is, when I move this script into the path (verified by echo $PATH) why does it then fail?
D'oh? Inquiring minds want to know how to make this work.
The . command is not normally used to run standalone scripts, and that seems to be what is confusing you. . is more typically used interactively to add new bindings to your environment (e.g. defining shell functions). It is also used to similar effect within scripts (e.g. to load a script "library").
Once you mark the script executable (per the comments on your question), you should be able to run it equally well from the current directory (e.g. ./safe.sh filename) or from wherever it is in the path (e.g. safe.sh filename).
You may want to remove .sh from the name, to fit with the usual conventions of command names.
BTW: I note that you mistakenly capitalize If in the script.
The error bad interpreter: Text file busy occurs if the script is open for write (see this SE question and this SF question). Make sure you don't have it open (e.g. in a editor) when attempting to run it.

Resources