clarification about bash script [duplicate] - linux

This question already has answers here:
Why can't I change directories using "cd" in a script?
(33 answers)
Closed 6 years ago.
I am new to bash scripting. This might be obvious to many. please bear with me.
I have a shell script as follows:
#!/bin/bash
echo `pwd`
cd /home/foo/bar
echo `pwd`
Let's say I am currently in dir : /home/foo1
If I execute the above script it prints:
/home/foo1
/home/foo/bar
But once the script completes execution, I have seen that it still remains in dir /home/foo1
I have also seen some scripts where there are explicit commands to reset the working dir using 'cd -' command.
If bash executes all the lines in the script as commands, why does it again reset the working dir?

When you are running an interactive session of bash, and from it, you execute a script (e.g. ./myscript.sh), then bash creates a new bash process to execute the script. Initially, that process get copy of the same environment as the original process (e.g. the current working directory, or environment variables), but if the script modifies the environment somehow, this changes only affect the new process, not the original one. So when the scripts exits, you go back to the original process which retains the original environment. So it is not possible to modify the current directory of the original shell from a script.
As a side note, the following line
echo `pwd`
does not make much sense. You either have to do echo $PWD or simply pwd.

Related

Which exactly are the system calls we can run via /bin/sh? [duplicate]

This question already has answers here:
Why can't I change directories using "cd" in a script?
(33 answers)
Closed 1 year ago.
I was running the Linux Shell commands in a particular way, I wanted to figure out if both ways of running them would generate the same result.
Example 1:
echo "echo "hi"" | /bin/sh
hi
Example 2:
echo "pwd" | /bin/sh
/root/test
Example 3:
Here, assume that there's a file called test.txt which only contains the word "test"
echo "cat test.txt" | /bin/sh
test
So far, everything seemed to working fine, but then when I typed the following
echo "cd .." | /bin/sh
Nothing happened, which shouldn't be the case, because if I type cd .. without | /bin/sh and press Enter, the Shell takes me back to the previous path which in this case would be /root
So, I just want to know what's the actual list of available commands for use via /bin/sh
You can run any command in this way, but they are executed by the inner shell, and so only have an effect within that shell.
Printing text to the screen using cat, echo or pwd is permanent, even after the inner shell has exited, because actually the inner shell writes to its standard output, and the outer shell (which you are using to type the commands) has linked the inner shell's output to its own output, which goes to the screen.
The idea of a "current working directory" is not system-wide, but it attached to a process like a shell. The cd command changes the current shell's working directory, but it does not effect the outer shell's working directory. Additionally, any new process started by a shell will start with the parent shell's working directory, but changing directory afterwards in either process will not have an effect on the other.
Environment variables are another thing that only have an effect on the current shell, and you get to choose whether environment variables are passed on to sub-processes by exporting them, or not.
For example, the following will give you the "correct" parent directory:
echo "cd ..; pwd" | /bin/sh
After running echo "cd .." | /bin/sh you get back to the previous folder because the above command runs a new shell instance, and it changes the current path inside the new subshell, and not into the caller instance.
For the same reason we never create helper script to change dir, but we use the aliases which run in the context of the calling shell.

Bash script output not showing up during execution? [duplicate]

This question already has answers here:
Can I export a variable to the environment from a Bash script without sourcing it?
(13 answers)
Closed 3 years ago.
I have created a virtual environment on my debian system and i made a script that activates it (should).
However when i execute the script nothing shows up, not even an error, my guess is that it is running in a different shell or something but I don't know how to solve it.
Here is the code of the script
#!/bin/bash
source ~/PythonEnv/environments/my_env/bin/activate
I have changed the permissions already with chmod u+x, so that is not a problem.
When i execute the script nothing shows up at all. Any thoughts???
Add set -x at the beginning of your bash script will do the trick.
-x Print commands and their arguments as they are executed.
You can see more bash options here
http://linuxcommand.org/lc3_man_pages/seth.html
Adding x-permissions is not necessary, since you are using source with an absolute path. Of course this sets the environment only which is executed by the shell script which you have posted here. If you want the changes in your interactive shell, it is pointless to do it inside a script. You have to source the activate script in your shell (respectively inside that process where you want the environment to be modified).

Changing bash prompt temporarily by own script [duplicate]

This question already has answers here:
Changing PS1 prompt in a Bash parent shell
(3 answers)
Closed 6 years ago.
I wanted to write a tiny shell script that shortens the commmand prompt when it gets too long. Setting the PS1 variable in bash works fine. When I try the same command directly in a script and run it, nothing happens.
#!/bin/bash
PS1='\u:\W\$ '
I tried eval "PS1='\u:\W\$ '" , export PS1='\u:\W\$ ' and exec PS1='\u:\W\$ ' without any result.
How can I achieve the same result as a direct input in the bash?
Thank you in advance
In general, in UNIX, a process can only change variables for itself and its children -- not its parent ("its parent" being the process that invoked it).
You need to source a script, not execute it, for it to be able to effect your interactive shell's variables. This executes all commands inside the script inside your current shell, not a new shell started as a child process (whose variables' values are thrown away on exit).
# in bash
source yourscript
# or in POSIX sh
. yourscript # mind the space!
In this usage, the shebang does nothing; similarly, the +x permission isn't needed either. It's also typical to name scripts intended to be sourced rather than executed with an extension mapping to the shell they're intended to be used by (yourscript.bash for bash, yourscript.sh for a script which can be sourced by any POSIX shell), whereas scripts intended to be executed rather than sourced should have no extension.

Bash Script To Add A Folder/Directory to the path in linux not working [duplicate]

This question already has an answer here:
Unable to export the variable through script file [duplicate]
(1 answer)
Closed 6 years ago.
I created a bash script to add
/My_Scripts/Bash_Scripts
to the default PATH of linux.
!/bin/bash
#This Script is used to add a folder/diectory to the PATH..
echo -e "\e[92m\e[1mCREATING PATH...........\n\n"
cd
mkdir My_Scripts
cd My_Scripts
mkdir Bash_Scripts
cd
export PATH=$PATH:$HOME/My_Scripts/Bash_Scripts
echo -e "\e[92m\e[1mPATH CREATON SUCCESSFUL\n \e[39m"
echo $PATH
The output of script is
root#kali:~/Desktop# bash add_path
CREATING PATH...........
PATH CREATON SUCCESSFUL
`/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/root/My_Scripts/Bash_Scripts'
but if I type echo $PATH in the terminal outside, the path is not added
root#kali:~/Desktop# $PATH
bash: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin: No such file or directory
You are starting up a new bash process and PATH is only modified in the context of the new process. When this process quits, changes done in its environment do not propagate to the parent process.
Instead, you would want to modify PATH in the context of current bash process. If you want this temporarily, you may source your script. source will run in the context of the current bash process. Beware of any side effects - like cd will change the directory, exit will terminate the current bash process.
If you want this change permanently for all future interactive sessions, you can modify ~/.bashrc.
Also, the syntax of shebang is #!/path/to/program, you are missing a #.
Your changes is affected in current shell only.Put the entry in .bashrc file. It will affect the all the terminal.open the .bashrc file and add the below line and run the file -
vim ~/.bashrc
export PATH="$PATH:/home/username"
~/.bashrc
Edit the parent shell
script.sh
#!/bin/bash
export "PATH=$PATH:$HOME/My_Scripts/Bash_Scripts"
echo $PATH
$~ PATH=$(./script.sh)
$~ echo $PATH
/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/home/loganaayahee/My_Scripts/Bash_Scripts
First thing - you should use echo $PATH. By simply typing $PATH you're trying to execute the command, hence the "No such file or directory error"
Next - the /root/My_Scripts/Bash_Scripts wasn't really added to the PATH. The first output you see in done inside the script, so the changes could be seen there.
The reason is that PATH will be set only in the context of the script shell, execute it as source add_path to preserve the changes in variables (but only for current shell).
If you want the variable to be persistant in all shells - add it to /.bashrc (since you're runnung as root).

Why calling a script by "scriptName" doesn't work?

I have a simple script cmakeclean to clean cmake temp files:
#!/bin/bash -f
rm CMakeCache.txt
rm *.cmake
which I call like
$ cmakeclean
And it does remove CMakeCache.txt, but it doesn't remove cmake_install.cmake:
rm: *.cmake: No such file or directory
When I run it like:
$ . cmakeclean
it does remove both.
What is the difference and can I make this script work like an usual linux command (without . in front)?
P.S.
I am sure the both times is same script is executed. To check this I added echo meme in the script and rerun it in both ways.
Remove the -f from your #!/bin/bash -f line.
-f prevents pathname expansion, which means that *.cmake will not match anything. When you run your script as a script, it interprets the shebang line, and in effect runs /bin/bash -f scriptname. When you run it as . scriptname, the shebang is just seen as a comment line and ignored, so the fact that you do not have -f set in your current environment allows it to work as expected.
. script is short for source script which means the current shell executes the commands in the script. If there's an exit in there, the current shell will exit (and e. g. the terminal window will close).
This is typically used to modify the environment of the current shell (set variables etc.).
script asks the shell to fork itself, then exec the given script in the child process, and then wait in the father for the termination of the child. If there's an exit in the script, this will be executed by the child shell and thus only terminate this. The father shell stays intact and unaltered by this call.
This is typically used to start other programs from the current shell.
Is this about ClearCase? What did you do in your poor life where you've been assigned to work in the deepest bowels of hell?
For years, I was a senior ClearCase Administer. I haven't touched it in over a decade. My life is way better now. The sky is bluer, bird songs are more melodious, and my dread over coming to work every day is now a bit less.
Getting back to your issue: It's hard to say exactly what's going on. ClearCase does some wacky things. In a dynamic view, the ClearCase repository on Unix systems is hidden in the shell's environment. Now you see it, now you don't.
When you run a shell script, it starts up a new environment. If a particular shell variable is not imported, it is invisible that shell script. When you merely run cmakeclean from the command line, you are spawning a new shell -- one that does not contain your ClearCase environment.
When you run a shell script with a dot prefix like . cmakeclean, you are running that shell script in the current shell which contains your ClearCase environment. Thus, it can see your ClearCase view.
If you're using a snapshot view, it is possible that you have a $HOME/.bashrc that's changing directories on you. When a new shell environment runs in BASH (the default shell in MacOS X and Linux), it first runs $HOME/.bashrc. If this sets a particular directory, then you end up in that directory and not in the directory where you ran your shell script. I use to see this when I too was involved in ClearCase hell. People setup their .kshrc script (it was the days before BASH and most people used Kornshell) to setup their views. Unfortunately, this made running any other shell script almost impossible to do.

Resources