简体   繁体   English

从 Bash 脚本更改当前目录

[英]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.我想在 Bash 中创建一个用于目录导航的实用程序。 I have created a test script that looks like the following:我创建了一个如下所示的测试脚本:

#!/bin/bash
cd /home/artemb

When I execute the script from the Bash shell the current directory doesn't change.当我从 Bash shell 执行脚本时,当前目录不会改变。 Is it possible at all to change the current shell directory from a script?是否有可能从脚本更改当前的 shell 目录?

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:相反,您可以像这样启动脚本:

. myscript.sh

The . . will evaluate the script in the current environment, so it might be altered将评估当前环境中的脚本,因此它可能会被更改

You need to convert your script to a shell function:您需要将脚本转换为 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
}

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.原因是每个进程都有自己的当前目录,当你从 shell 执行一个程序时,它会在一个新进程中运行。 The standard "cd", "pushd" and "popd" are builtin to the shell interpreter so that they affect the shell process.标准的“cd”、“pushd”和“popd”内置于shell解释器中,因此它们会影响shell进程。

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.通过使您的程序成为 shell 函数,您将添加自己的进程内命令,然后任何目录更改都会反映在 shell 进程中。

In light of the unreadability and overcomplication of answers, i believe this is what the requestor should do鉴于答案的不可读性和过于复杂,我认为这是请求者应该做的

  1. add that script to the PATH将该脚本添加到PATH
  2. run the script as . scriptname将脚本作为. scriptname . scriptname

The . . (dot) will make sure the script is not run in a child shell. (dot) 将确保脚本不在子 shell 中运行。

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.每次您想将脚本提供给 shell 环境时,或者如果您只是不想记住必须这样做才能使脚本正常工作。

If you are using bash you can try alias:如果您使用 bash,您可以尝试别名:

into the .bashrc file add this line:在 .bashrc 文件中添加这一行:

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

when you write "p" on the command line, it will change the directory.当你在命令行上写“p”时,它会改变目录。

If you run a bash script then it will operates on its current environment or on those of its children, never on the parent.如果您运行 bash 脚本,那么它将在其当前环境或其子项上运行,而不是在父项上运行。

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 :如果目标是运行您的命令:goto.sh /home/test 然后在 /home/test 中交互工作,一种方法是在您的脚本中运行 bash 交互式子shell:

#!/bin/bash
cd $1
exec bash

This way you will be in /home/test until you exit ( exit or Ctrl+C ) of this shell.这样,您将在 /home/test 中,直到您退出( exit 或 Ctrl+C )此 shell。

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将当前目录推送到目录堆栈上,并将其更改为给定目录, popd获取堆栈顶部的目录,然后更改为该目录。

pushd ../new/dir > /dev/null
# do something in ../new/dir
popd > /dev/null

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现在您可以在终端中使用: yourcommand

I've made a script to change directory.我已经制作了一个脚本来更改目录。 take a look: https://github.com/ygpark/dj看一看: https : //github.com/ygpark/dj

Basically we use cd.. to come back from every directory.基本上我们使用cd..从每个目录返回。 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 .您可以使用 alias 命令使用单独的脚本文件来实现这一点。 For example:例如:

code.sh代码.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 :在当前 shell 中使用source code.sh ,您可以使用:

$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.那里还解释了如何将代码放在 ~/.bashrc 中,以便每个新打开的 shell 都会自动拥有这个新的别名命令。 You can add new command to go to specific directories by modifying the code by adding more if conditions and different arguments.您可以通过添加更多if conditions和不同参数来修改代码,从而添加新命令以转到特定目录。 You can also pull the code from git overhere .你也可以从 git 中提取代码到这里

在您的 shellscript 中添加以下 cd 行:

exec $SHELL

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.假设在您是管理员的个人 iMac 上,在打开命令窗口时的默认目录 /Users/jdoe 下,这将是要转到的目录:/Users/jdoe/Desktop/Mongo/db.3.2.1 /斌。

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. vi mongobin,我在其中输入: cd /Users/jdoe/Desktop/Mongo/db.3.2.1/bin作为第一行。
  2. chmod 755 mongobin
  3. source mongobin
  4. pwd

Voila!瞧!

I like to do the same thing for different projects without firing up a new shell.我喜欢在不启动新 shell 的情况下为不同的项目做同样的事情。

In your case:在你的情况下:

cd /home/artemb

Save the_script as:将 the_script 保存为:

echo cd /home/artemb

Then fire it up with:然后启动它:

\`./the_script\`

Then you get to the directory using the same shell.然后您使用相同的shell 进入该目录。

I've also created a utility called goat that you can use for easier navigation.我还创建了一个名为goat的实用程序,您可以使用它来更轻松地导航。

You can view the source code on GitHub .您可以在GitHub 上查看源代码。

As of v2.3.1 the usage overview looks like this:v2.3.1 开始使用概述如下所示:

# 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

Declare your path:声明你的路径:

PATH='/home/artemb'     
cd ${PATH}

This is my current way of doing it for bash (tested on Debian).这是我目前为 bash 做的方式(在 Debian 上测试)。 Maybe there's a better way:也许有更好的方法:

Don't do it with exec bash, for example like this:不要用 exec bash 来做,例如这样:

#!/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.因为虽然它看起来可以工作,但在运行它并完成脚本之后,是的,您将位于正确的目录中,但您将位于子shell 中,之后您可以通过按 Ctrl+D 来确认,然后您将看到它退出子shell,将您放回原始目录。

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.这通常不是您希望脚本用户在他们运行的脚本返回后留下的状态,因为不明显的是,他们处于子 shell 中,现在他们基本上打开了两个 shell,而他们认为只有一个 shell。 They might continue using this subshell and not realize it, and it could have unintended consequences.他们可能会继续使用这个子 shell 而没有意识到它,这可能会产生意想不到的后果。

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.如果您真的希望脚本退出并在新目录中打开一个子 shell,最好更改 PS1 变量,以便脚本用户有一个视觉指示器,表明他们仍然打开了一个子 shell。

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.它是两个文件,一个是直接调用的 outer.sh,另一个是来自于 outer.sh 脚本的inner.sh。 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.之后它会制作当前用户的 ~/.bashrc 文件的临时副本,为其中的 PS1 变量添加一个覆盖,以及一个清理例程,最后它运行 exec bash --rcfile 指向 .bashrc.tmp 文件使用修改后的环境初始化 bash,包括修改后的提示和清理例程。

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.在outer.sh 退出后,您将被留在所需目录(在本例中为 testdir/ 由inner.sh 脚本输入)的子shell 中,并带有一个视觉指示器,让您清楚,如果您退出在子 shell 中,.bashrc.tmp 文件将被清理例程删除,您将返回到您开始的目录中。

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:也许有更聪明的方法来做到这一点,但这是我在大约 40 分钟的实验中找到的最好方法:

file 1: outer.sh文件 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文件 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:然后使用 exec bash 将您放入您的子 shell,但使用修改后的提示,这使得这一点很明显,例如:

(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如果你 Ctrl-D 退出子shell,它应该通过删除 testdir/ 目录中的临时 .bashrc.tmp 文件来清理

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...我想知道是否有比复制 .bashrc 文件更好的方法,尽管在子外壳中正确更改 PS1 变量...

This is a simplified compilation of above answer.这是上述答案的简化汇编。
Create a shell file shellfile.sh In the script change your directory inside a function创建一个 shell 文件shellfile.sh在脚本中更改您在函数内的目录

#!/bin/bash

cd folder1/folder2/

Now run the script with .现在运行脚本. before it.在它之前。
. uses the current thread/session to execute the script.使用当前线程/会话来执行脚本。

. shellfile.sh

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM