Changing a directory of the parent shell [duplicate] - bash

This question already has answers here:
Why can't I change directories using "cd" in a script?
(33 answers)
Closed 4 years ago.
I 'm wondering of any mechanism that one could use to change the directory of a parent shell from sub-shell. For ex., I 'm running the script "settings.sh" in my $HOME. My $HOME has a directory $HOME/TEST/run. If my "settings.sh" scripts is as below
#!/bin/bash
# some shell related code
# some shell related code
cd $HOME/TEST/run
exit 0
I execute the above script at command prompt at $HOME. After the execution, I expect my command prompt in directory $HOME/TEST/run. I do understand that in sub-shell, it is being cd'd to $HOME/TEST/run, but at the end of the execution, it's back in $HOME.
Is there any elegant way of doing the above, using a single script. One way is to modify the script "settings.sh" to generate another script and then use ". $HOME/generatedScript.sh"

Nope, you can't. That's by design. Parent processes should never be affected by the results of a child without them wanting to be affected (otherwise sub-shells could do all sorts of nasty tricky things to the parent).
What you can do is have the shell save the information into a file or print the directory or ... Such that the parent at least can use it to change directories if the parent wants to.

Wes Hardaker explained the reasoning behind why executing that script does not cause it to change the directory of the parent shell. In order to work around that type of issue, you must "souce" the script instead of execute it. This causes the commands in the script to run in the current shell, rather than a child process.
. ./settings.sh
The first "." is a command which tells the shell to "source" the specified file. Here is the documentation from help .:
.: . filename [arguments]
Execute commands from a file in the current shell.
Read and execute commands from FILENAME in the current shell. The
entries in $PATH are used to find the directory containing FILENAME.
If any ARGUMENTS are supplied, they become the positional parameters
when FILENAME is executed.
Exit Status:
Returns the status of the last command executed in FILENAME; fails if
FILENAME cannot be read.

Related

Running executables without ./ or bash or source

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.

Running a cd command after user input in bash script will not change directory [duplicate]

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 trying to create a script whereby I have list of numerical test folders and want users to be able to cd into one of them after inputting the folder number.
The script correctly concatenates the input but on running the script it does not actually execute the cd command to the required directory?
It echo's to the screen but then just sits there as if awaiting a further prompt?
Can anyone advise what I am missing please? Script 'chgdir' is as below:
#!/bin/bash
#
# Script to move to test##dir (using input from user for dir number)
echo "Enter test directory number as ## and hit Return"
read dirnum
echo "cd /home/John/test$dirnum""dir"
However on running the script outputs the command to the screen but does not 'cd' and just remains in ~/bin?
cd /home/John/test01dir
John#John-PC ~/bin
P.S I am completely new to bash scripting as you can tell so any help really appreciated.
All your script does is to echo the command that you formed. You need to actually execute the cd command as well as just echoing it.
cd /home/John/test ${dirnum}dir
The {} around the variable name allows the shell to distinguish the variable name from the extra characters appended after it.
That will change the directory inside the script. To have it apply afterwards, you will need to source the script (with dot "." or "source") to affect the shell you are running in.
Your script just prints the command. That's all the echo command does. It doesn't execute it, because you didn't tell it to.
You could execute the cd command by replacing the echo command with this:
cd "/home/John/test${dirnum}dir"
But if that's the last line of your script, it won't do anything useful. Doing a cd inside a script doesn't affect anything but the script itself.
If you want to cd from a script and have it take effect in the invoking shell, you can source the script rather than executing it:
. ./thescript
or you can have the script print the command you want to execute and eval its output:
eval "`./thescript`"
(To be clear, if you source the script using the . command, it needs to execute the cd command; if you val its output, the script needs to print the command.)

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.

Bash can't cd into a directory through another script [duplicate]

This question already has answers here:
Why can't I change directories using "cd" in a script?
(33 answers)
Closed 7 years ago.
A while ago I wrote a script (let's call it myScript) so that it would cd into a specific folder. I saved it in cygwin home directory so I could run it just by calling ~/myScript. I had problems with it, but got it working by calling . ~/myScript
I have written a parent script (let's call it parentScript) that does few tasks and wanted to add an option so it would cd to my specific directory by calling myScript inside it.
myScript looks something like this:cd /cygdrive/c/Users/USER_NAME
parentScript has this:
if [ "${1}" -eq CD_TO_USER_NAME_OPTION ]; then
. ~/myScript
fi
This gives me the same problem I had before with myScript. It cds in the subshell, but then exits leaving me in the directory I started with. I want to be able to run myScript without using the parent that's why I didn't put in parentScript (like grep -E and Egrep).
What am I doing wrong??
You would need to invoke parentScript by sourcing it as well:
. parentScript
Then, in whatever script contains that, you would need to make sure the first argument is
./grandparentScript CD_TO_USER_NAME_OPTION
A script invoked by any other means besides sourcing is run in a new process. A process has its own current working directory (man 3 getcwd). That directory is inherited from the parent process, but the parent doesn't get it from the child when the child exits. The only way to have an inner script change the working directory of an outer script is by running them in the same process. That is done most simply by sourcing, or the . command, as you've discovered.
Another solution would be to use a shell function for your directory change:
magicCd() {
cd my/special/place
}
However, to avoid mixing procedural code with data, maybe the best choice would be simply to use the builtin cd command and store the desired destination in a variable.
my_special_place="$HOME/my/special/place"
cd "$my_special_place"
This last is just as abstract as the sourced script, function or alias, and much more obvious to any maintenance programmer who comes along.
This would be better done via an alias than a shell script:
$ alias myscript="cd /to/some/directory"
Then executing myscript will put you in that directory:
$ myscript
$ pwd
/to/some/directory

How to run 'cd' in shell script and stay there after script finishes?

I used 'change directory' in my shell script (bash)
#!/bin/bash
alias mycd='cd some_place'
mycd
pwd
pwd prints some_place correctly, but after the script finished my current working directory doesn't change.
Is it possible to change my path by script?
You need to source the file as:
. myfile.sh
or
source myfile.sh
Without sourcing the changes will happen in the sub-shell and not in the parent shell which is invoking the script. But when you source a file the lines in the file are executed as if they were typed at the command line.
While sourcing the script you want to run is one solution, you should be aware that this script then can directly modify the environment of your current shell. Also it is not possible to pass arguments anymore.
Another way to do, is to implement your script as a function in bash.
function cdbm() {
cd whereever_you_want_to_go
echo arguments to the functions were $1, $2, ...
}
This technique is used by autojump:
http://github.com/joelthelion/autojump/wiki
to provide you with learning shell directory bookmarks.
The script is run in a separate subshell. That subshell changes directory, not the shell you run it in. A possible solution is to source the script instead of running it:
# Bash
source yourscript.sh
# or POSIX sh
. yourscript.sh
It can be achieved by sourcing. Sourcing is basically execute the script in the same shell whereas normal execution(sh test.sh or ./test.sh) will create sub shell and execute script there.
test.sh
cd development/
ls
# Do whatever you want.
Execute test.sh by
source test.sh
. is shortest notation for source. So you can also do by
. test.sh
This will execute the script and change the directory of current shell to development/.
whenever you run a script on your login shell, a new subprocess is spawned and the script execution is done in a subshell.Once the script completes, the subshell exits and you are returned to the login shell.Hence whenever you do a cd through a script,the directory is changed to the path specified by cd, but by the time script finishes you come back to your login shell to the working directory from where you started the script.
The way to overcome this is use,
source yourscript.sh
what source does is it executes the script as TCL script, i.e it has the same effect as when you typed each line on the command line of your login shell and it executed from there. So this way when the script finishes after cd , it stays in that directory.
Another practical solution is to end your script by opening another shell session.
For instance:
#!/bin/bash
cd some_place
bash
This is useful, in my case, for scripts located in my ~/bin for instance, called from any other place. It is just a bit painful to type source ~/bin/mygoodoldscript instead of mygoo<TAB><ENTER>.
The downside is that the additional shell takes up a few more resources (not much).
Though there are answers. I think the intention of question is to use script to navigate to specific path.
Here is a simple practical solution works here without cancel out existing terminal environment flag.
provide a bash/tch/sh script to work for path generation
/* .goto.sh */
#!/usr/bin/env bash
echo '~/workspace'
add alias to the script output
alias goto 'cd `.goto.sh`'

Resources