Linux shell change directory

Script to change current directory (cd, pwd)

It is an expected behavior. The script is run in a subshell, and cannot change the parent shell working directory. Its effects are lost when it finishes.

To change the current shell’s directory permanently you should use the source command, also aliased simply as . , which runs a script in the current shell environment instead of a sub shell.

The following commands are identical:

@Sony: Note that you should use return to escape from a script sourced in this way, not exit — they are like shell functions, and exit will exit the shell that sourced the script.

1. . and source are equal in bash. 2. we don’t need to use ./ before filename if it’s in the same directory. It is ok to run only this: . script

For small tasks such as this, instead of creating script, create an alias like this,

$ alias cdproj='cd /dir/web/www/proj' 

You should add this to your .bashrc file, if you want it set for every interactive shell.

Now you can run this as $ cdproj .

You can also have the script echo the commands to be executed, and then use eval `./script` or eval $(./script) to execute those commands. This is a common approach for commands that need to update the invoking shell’s environment.

As a reminder, you can execute multiple commands in a single alias (effectively making it similar to a script). You can delimit them by semi-colons or such.

Use exec bash at the end

A bash script operates on its current environment or on that of its children, but never on its parent environment.

However, this question often gets asked because one wants to be left at the bash prompt in a certain directory after the execution of a bash script from another directory.

If this is the case, simply execute a child bash instance at the end of the script:

#!/usr/bin/env bash cd desired/directory exec bash 

This creates a new subshell. Type Ctrl + D or exit to return to the first shell where the script was initially started.

UPDATE: Use $SHELL at the end

At least with newer versions of bash , the exec on the last line is no longer required. Furthermore, the script can be made to work with whatever preferred shell by using the $SHELL environment variable. This then gives:

#!/usr/bin/env bash cd desired/directory $SHELL 

Better to just source the script, as in accepted answer: using exec is typically considered the last resort of a scoundrel.. 🙂

Since nobody has detailed the problems with this (I’m looking at you, @Dennis): (1) Each time you run this, it creates a new, persistent bash process. Do it ten or twenty times in a session, and you’ll have 11 to 21 bash processes piled up. This may affect performance, and, if you try to terminate the session cleanly by typing exit (or Ctrl+D), you’ll have to do that 11 to 21 times. (2) Another drawback of using an executable script is that, if you set any shell options (e.g., dotglob or globstar ) in your interactive shell session, you will lose them, because you’re starting a new shell.

Читайте также:  Compiling with mingw linux

Very nice solution! I’ve rewritten my alias in bash_profile so now it is a script stored in a separate file. I use the script to go to a newly created temporary folder. And now it is even easier to have a temporary bash session. SRP in action! Thanks!

Источник

Change the current directory from a Bash script

Is it possible to change current directory from a script? I want to create a utility for directory navigation in Bash. I have created a test script that looks like the following:

When I execute the script from the Bash shell the current directory doesn’t change. Is it possible at all to change the current shell directory from a script?

Just an enhancement suggestion: if you use pushd (possibly redirected to >/dev/null to suppress its output) instead of cd , you can later return to the previous directory with popd .

17 Answers 17

When you start your script, a new process is created that only inherits your environment. When it ends, it ends. Your current environment stays as it is.

Instead, you can start your script like this:

The . will evaluate the script in the current environment, so it might be altered

+1 because you’re right. Though I sincerely doubt he’ll want to source a directory changing script each time he needs it. Moreover, .sh extensions are totally eww. Don’t use them.

Yes, usually it is better not to use it that way. Most of the time you are glad that your current environment does not suffer. But then I have scripts to do some setup tasks for me including changing to the right place and then I . them, too. Btw. .sh is of course a matter of personal style. I probably wouldn’t use it while installing scripts system wide. But in my ~/bin I use them to know what is what 🙂

To me the reasoning in that article is bogus. It seems that the result has been known upfront but finding reasons for it wasn’t that easy. So I stand my point it is a matter of personal style, nothing else.

You need to convert your script to a shell function:

#!/bin/bash # # this script should not be run directly, # instead you need to source it from your .bashrc, # by adding this line: # . ~/bin/myprog.sh # function myprog() < A=$1 B=$2 echo "aaa $bbb $ ccc" cd /proc > 

The reason is that each process has its own current directory, and when you execute a program from the shell it is run in a new process. The standard «cd», «pushd» and «popd» are builtin to the shell interpreter so that they affect the shell process.

By making your program a shell function, you are adding your own in-process command and then any directory change gets reflected in the shell process.

+1. One thing which I noticed was in the file, we have to define the function before calling it. It might help someone as inexperienced as me.

Once I’ve created this myprog.sh file and added it to the .bashrc how do I run the script? Should I call my function from another shell file or directly from the shell? It seems it doesn’t work in neither ways.

@AndreaSilvestri Either log out and log back in or source .bashrc. Adding it to .bashrc doesn’t do anything until .bashrc is run.

@winden, please avoid teaching the function keyword, and especially combining function with () s after the name. function myfunc < is legacy ksh syntax that bash implements for backwards compatibility; myfunc() < is modern POSIX syntax that all standard-compliant shells are required to support; function myfunc() < merges the two in a way that's incompatible with both legacy ksh and modern POSIX sh. See wiki.bash-hackers.org/scripting/obsolete

Читайте также:  Qualcomm atheros ar9462 driver linux

In light of the unreadability and overcomplication of answers, i believe this is what the requestor should do

The . (dot) will make sure the script is not run in a child shell.

Putting the above together, you can make an alias

if you don’t want to write the leading «.» each time you want to source your script to the shell environment, or if you simply don’t want to remember that must be done for the script to work correctly.

@SDsolar You need to add this to your ~/.bashrc file to make it persistent. Works like a charm for me.

If you are using bash you can try alias:

into the .bashrc file add this line:

alias p='cd /home/serdar/my_new_folder/path/' 

when you write «p» on the command line, it will change the directory.

+1 for alias. shell function is interesting but the OP asked for a simple nav with cd. I’m guessing most people need a script like this to navigate source code branches and for that alias is sufficient

If you run a bash script then it will operates on its current environment or on those of its children, never on the parent.

If goal is to run your command : goto.sh /home/test Then work interactively in /home/test one way is to run a bash interactive subshell within your script :

This way you will be in /home/test until you exit ( exit or Ctrl+C ) of this shell.

I thought this would fix the problem for a shell script I was running but instead it starts the shell and forgets what I wanted.

With pushd the current directory is pushed on the directory stack and it is changed to the given directory, popd get the directory on top of the stack and changes then to it.

pushd ../new/dir > /dev/null # do something in ../new/dir popd > /dev/null 
yourusername/.bashrc (or yourusername/.bash_profile on MAC) by an editor 

and add this code next to the last line:

alias yourcommand="cd /the_path_you_wish" 
source ~/.bashrc or source ~/.bash_profile on MAC. 

now you can use: yourcommand in terminal

I’ve made a script to change directory. take a look: https://github.com/ygpark/dj

Basically we use cd.. to come back from every directory. I thought to make it more easy by giving the number of directories with which you need to come back at a time. You can implement this using a separate script file using the alias command . For example:

#!/bin/sh _backfunc() < if [ "$1" -eq 1 ]; then cd .. elif [ "$1" -eq 2 ]; then cd ../.. elif [ "$1" -eq 3 ]; then cd ../../.. elif [ "$1" -eq 4 ]; then cd ../../../.. elif ["$1" -eq 10]; then cd /home/arun/Documents/work fi >alias back='_backfunc' 

After using source code.sh in the current shell you can use :

to come two steps back from the current directory. Explained in detail over here. It is also explained over there how to put the code in ~/.bashrc so that every new shell opened will automatically have this new alias command. You can add new command to go to specific directories by modifying the code by adding more if conditions and different arguments. You can also pull the code from git over here.

Читайте также:  Linux установить владельца папки рекурсивно

Add below cd line in your shellscript this:

This is a simplified compilation of above answer.
Create a shell file shellfile.sh In the script change your directory inside a function

#!/bin/bash cd folder1/folder2/ 

Now run the script with . before it.
. uses the current thread/session to execute the script.

This is my current way of doing it for bash (tested on Debian). Maybe there’s a better way:

Don’t do it with exec bash, for example like this:

because while it appears to work, after you run it and your script finishes, yes you’ll be in the correct directory, but you’ll be in it in a subshell, which you can confirm by pressing Ctrl+D afterwards, and you’ll see it exits the subshell, putting you back in your original directory.

This is usually not a state you want a script user to be left in after the script they run returns, because it’s non-obvious that they’re in a subshell and now they basically have two shells open when they thought they only had one. They might continue using this subshell and not realize it, and it could have unintended consequences.

If you really want the script to exit and leave open a subshell in the new directory, it’s better if you change the PS1 variable so the script user has a visual indicator that they still have a subshell open.

Here’s an example I came up with. It is two files, an outer.sh which you call directly, and an inner.sh which is sourced inside the outer.sh script. The outer script sets two variables, then sources the inner script, and afterwards it echoes the two variables (the second one has just been modified by the inner script). Afterwards it makes a temp copy of the current user’s ~/.bashrc file, adds an override for the PS1 variable in it, as well as a cleanup routine, and finally it runs exec bash —rcfile pointing at the .bashrc.tmp file to initialize bash with a modified environment, including the modified prompt and the cleanup routine.

After outer.sh exits, you’ll be left inside a subshell in the desired directory (in this case testdir/ which was entered into by the inner.sh script) with a visual indicator making it clear to you, and if you exit out of the subshell, the .bashrc.tmp file will be deleted by the cleanup routine, and you’ll be back in the directory you started in.

Maybe there’s a smarter way to do it, but that’s the best way I could figure out in about 40 minutes of experimenting:

file 1: outer.sh

#!/bin/bash var1="hello" var2="world" source inner.sh echo $var1 echo $var2 cp ~/.bashrc .bashrc.tmp echo 'export PS1="(subshell) $PS1"' >> .bashrc.tmp cat > .bashrc.tmp cleanup() < echo "cleaning up. " rm .bashrc.tmp >trap 'cleanup' 0 EOS exec bash --rcfile .bashrc.tmp 

file 2: inner.sh

$ mkdir testdir $ chmod 755 outer.sh $ ./outer.sh 

and then drop you into your subshell using exec bash, but with a modified prompt which makes that obvious, something like:

(subshell) user@computername:~/testdir$ 

and if you Ctrl-D out of the subshell, it should clean up by deleting a temporary .bashrc.tmp file in the testdir/ directory

I wonder if there’s a better way than having to copy the .bashrc file like that though to change the PS1 var properly in the subshell.

Источник

Оцените статью
Adblock
detector