228

是否可以从脚本更改当前目录?

我想为 Bash 中的目录导航创建一个实用程序。我创建了一个如下所示的测试脚本:

#!/bin/bash
cd /home/artemb

当我从 Bash shell 执行脚本时,当前目录不会改变。是否可以从脚本更改当前的 shell 目录?

4

17 回答 17

255

当您启动脚本时,将创建一个仅继承您的环境的新进程。当它结束时,它就结束了。您当前的环境保持原样。

相反,您可以像这样开始您的脚本:

. myscript.sh

.在当前环境中评估脚本,因此它可能会被更改

于 2009-05-17T12:02:35.990 回答
198

您需要将脚本转换为 shell 函数:

#!/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 ${A} bbb ${B} ccc"
  cd /proc
}

原因是每个进程都有自己的当前目录,当您从 shell 执行程序时,它会在新进程中运行。标准的“cd”、“pushd”和“popd”内置于 shell 解释器中,因此它们会影响 shell 进程。

通过使您的程序成为 shell 函数,您正在添加自己的进程内命令,然后任何目录更改都会反映在 shell 进程中。

于 2009-05-17T12:46:45.477 回答
61

鉴于答案的不可读性和过于复杂,我相信这是请求者应该做的

  1. 将该脚本添加到PATH
  2. run the script as . scriptname

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

于 2009-09-01T20:37:27.390 回答
43

Putting the above together, you can make an alias

alias your_cmd=". your_cmd"

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.

于 2010-08-16T08:09:32.190 回答
35

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.

于 2010-05-11T12:25:23.273 回答
22

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 :

#!/bin/bash
cd $1
exec bash

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

于 2013-03-01T19:56:30.990 回答
19

使用pushd将当前目录推送到目录堆栈并更改为给定目录,popd获取堆栈顶部的目录,然后更改为该目录。

pushd ../new/dir > /dev/null
# do something in ../new/dir
popd > /dev/null
于 2009-05-17T12:18:26.480 回答
5

Simply go to

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"

Then quit editor.

Then type:

source ~/.bashrc or source ~/.bash_profile on MAC.

now you can use: yourcommand in terminal

于 2015-10-28T05:14:13.197 回答
3

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

于 2014-03-06T05:17:56.420 回答
3

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:

code.sh

#!/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 :

$back 2 

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.

于 2014-12-04T17:22:23.977 回答
2

Add below cd line in your shellscript this:

exec $SHELL
于 2019-03-08T11:55:19.967 回答
1

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.

. shellfile.sh
于 2021-08-17T16:44:50.620 回答
0

This approach is easier for me.

Suppose on a personal iMac where you are an admin, under the default directory when a command window is opened, /Users/jdoe, this will be the directory to go to: /Users/jdoe/Desktop/Mongo/db.3.2.1/bin.

These are the steps that can have the job done:

  1. vi mongobin, in which I entered: cd /Users/jdoe/Desktop/Mongo/db.3.2.1/bin as the first line.
  2. chmod 755 mongobin
  3. source mongobin
  4. pwd

Voila!

于 2016-02-07T20:00:55.147 回答
0

I've also created a utility called goat that you can use for easier navigation.

You can view the source code on GitHub.

As of v2.3.1 the usage overview looks like this:

# Create a link (h4xdir) to a directory:
goat h4xdir ~/Documents/dev

# Follow a link to change a directory:
cd h4xdir

# Follow a link (and don't stop there!):
cd h4xdir/awesome-project

# Go up the filesystem tree with '...' (same as `cd ../../`):
cd ...

# List all your links:
goat list

# Delete a link (or more):
goat delete h4xdir lojban

# Delete all the links which point to directories with the given prefix:
goat deleteprefix $HOME/Documents

# Delete all saved links:
goat nuke

# Delete broken links:
goat fix
于 2018-01-11T19:18:15.710 回答
0

Declare your path:

PATH='/home/artemb'     
cd ${PATH}
于 2019-06-27T08:37:33.643 回答
0

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:

#!/bin/bash
cd $1
exec bash

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 <<EOS >> .bashrc.tmp
cleanup() {
    echo "cleaning up..."
    rm .bashrc.tmp
}

trap 'cleanup' 0
EOS

exec bash --rcfile .bashrc.tmp

file 2: inner.sh

cd testdir
var2="bird"

then run:

$ mkdir testdir
$ chmod 755 outer.sh

$ ./outer.sh

it should output:

hello
bird

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...

于 2020-11-18T23:11:37.857 回答
-1

I like to do the same thing for different projects without firing up a new shell.

In your case:

cd /home/artemb

Save the_script as:

echo cd /home/artemb

Then fire it up with:

\`./the_script\`

Then you get to the directory using the same shell.

于 2018-01-11T19:03:44.947 回答