为什么我不能在脚本中使用“cd”更改目录?

我正在尝试编写一个小脚本来将当前目录更改为我的项目目录:

#!/bin/bashcd /home/tree/projects/java

我将此文件保存为proj,添加了chmod的执行权限,并将其复制到/usr/bin。当我通过以下方式调用它时:proj,它什么也没做。我做错了什么?

710211 次浏览

Shell脚本在子shell中运行,每个子shell都有自己的当前目录概念。cd成功,但一旦子shell退出,您就会回到交互式shell中,那里没有任何变化。

解决这个问题的一种方法是使用别名:

alias proj="cd /home/tree/projects/java"

您没有做错任何事!您更改了目录,但仅在运行脚本的子shell中。

您可以使用“点”命令在当前进程中运行脚本:

. proj

但我更喜欢格雷格的建议,在这个简单的情况下使用别名。

当您触发外壳脚本时,它会运行该shell的新的实例(/bin/bash)。因此,您的脚本只需启动一个shell,更改目录并退出。换句话说,外壳脚本中的cd(和其他类似命令)不影响也无法访问它们启动的shell。

它只更改脚本本身的目录,而您的当前目录保持不变。

您可能希望使用符号链接代替。它允许您创建文件或目录的“快捷方式”,因此您只需键入cd my-project之类的内容。

您可以执行以下操作:

#!/bin/bashcd /your/project/directory# start another shell and replacing the currentexec /bin/bash

编辑:这也可以“点缀”,以防止创建后续shell。

示例:

. ./previous_script  (with or without the first line)

Jeremy Ruten使用符号链接的想法引发了一个没有跨越任何其他答案的想法。使用:

CDPATH=:$HOME/projects

前导冒号很重要;这意味着如果当前目录中有目录'dir',那么'cd dir'将更改为该目录,而不是跳到其他地方。设置如图所示的值后,您可以执行:

cd java

而且,如果当前目录中没有名为java的子目录,那么它将直接带您到$HOME/项目/java-没有别名,没有脚本,没有可疑的执行人员或点命令。

我的$HOME /Users/jleffler;我的$CDPATH是:

:/Users/jleffler:/Users/jleffler/mail:/Users/jleffler/src:/Users/jleffler/src/perl:/Users/jleffler/src/sqltools:/Users/jleffler/lib:/Users/jleffler/doc:/Users/jleffler/work

您可以组合别名和脚本,

alias proj="cd \`/usr/bin/proj !*\`"

前提是脚本与目标路径相呼应。请注意,这些是围绕脚本名称的反引号。

例如,您的脚本可能是

#!/bin/bashecho /home/askgelal/projects/java/$1

这种技术的优点是脚本可以采用任意数量的命令行参数并通过可能复杂的逻辑计算发出不同的目标。

cd是在脚本的shell中完成的。当脚本结束时,该shell退出,然后你被留在你所在的目录中。“源”脚本,不要运行它。而不是:

./myscript.sh

. ./myscript.sh

(注意脚本名称前的点和空格。)

要创建一个将cd到选择目录的bash脚本:

创建脚本文件

#!/bin/sh# file : /scripts/cdjava#cd /home/askgelal/projects/java

然后在启动文件中创建别名。

#!/bin/sh# file /scripts/mastercode.sh#alias cdjava='. /scripts/cdjava'

  • 我创建了一个启动文件,在其中我转储了所有别名和自定义函数。
  • 然后我将此文件源到我的. bashrc中,以便在每次启动时设置它。

例如,创建一个主别名/函数文件:/scripts/mastercode.sh
(将别名放入此文件中。)

然后在您的. bashrc文件末尾:

source /scripts/mastercode.sh



现在很容易cd到您的java目录,只需键入cdjava,您就在那里。

我做了以下事情:

创建一个名为case的文件

将以下内容粘贴到文件中:

#!/bin/sh
cd /home/"$1"

保存它,然后:

chmod +x case

我还在我的.bashrc中创建了一个别名:

alias disk='cd /home/; . case'

现在当我键入:

case 12345

基本上我正在输入:

cd /home/12345

您可以在“case”之后键入任何文件夹:

case 12
case 15
case 17

这就像打字:

cd /home/12
cd /home/15
cd /home/17

分别

在我的情况下,路径要长得多——这些家伙用前面的信息总结了一下。

脚本中的cd在技术上是工作,因为它更改了运行脚本的shell的目录,但这是与交互式shell分叉的单独进程。

解决这个问题的一种与POSVI兼容的方法是定义shell过程而不是shell调用的命令脚本

jhome () {cd /home/tree/projects/java}

您可以将其键入或放入各种shell启动文件之一。

您可以结合Adam&Greg的别名和点方法来制作更具动态性的东西-

alias project=". project"

现在运行项目别名将在当前shell中执行项目脚本,而不是子shell。

在我的特殊情况下,我需要多次更改同一个目录。所以在我的. bashrc(我使用ubuntu)上我添加了

1-

$nano~./bashrc

 function switchp{cd /home/tree/projects/$1}

2-

$source~/. bashrc##获取资源

3-

java交换机

直接它会做:CD /home/tree/projects/java

希望有帮助!

我让我的代码使用. <your file name>工作

./<your file name>不起作用,因为它不会更改终端中的目录,它只是更改特定于该脚本的目录。

这是我的程序

#!/bin/bashecho "Taking you to eclipse's workspace."cd /Developer/Java/workspace

这是我的终端

nova:~ Kael$nova:~ Kael$ . workspace.shTaking you to eclipe's workspace.nova:workspace Kael$

如果你使用作为shell,最好的解决方案是创建一个函数。例如,给定最初的问题,你可以复制下面的4行并将它们粘贴到你的fish命令行中:

function projcd /home/tree/projects/javaendfuncsave proj

这将创建函数并将其保存以供以后使用。如果您的项目发生变化,只需使用新路径重复该过程。

如果您愿意,您可以通过执行以下操作手动添加函数文件:

nano ~/.config/fish/functions/proj.fish

并输入文本:

function projcd /home/tree/projects/javaend

最后按ctrl+x退出,然后按y返回保存更改。

注意:使用函数保存的第一种方法为您创建proj.fish文件)。

您可以使用运算符&&:

cd myDirectory&&ls

如果以反斜杠结束行,则可以在同一子shell中执行某些行。

cd somedir; \pwd

在你的~/.bash_profile文件中.添加下一个函数

move_me() {cd ~/path/to/dest}

重新启动终端,您可以键入

move_me

您将被移动到目标文件夹。

我有一个名为p的简单bash脚本来管理
github.com/godzilla/bash-stuff
上的目录更改只需将脚本放在本地bin目录(/usr/Local/bin)
并将

alias p='. p'

在您的. bashrc

虽然寻找您要运行的脚本是一种解决方案,但您应该意识到此脚本可以直接修改当前shell的环境。此外,无法再传递参数。

另一种方法是将脚本实现为bash中的函数。

function cdbm() {cd whereever_you_want_to_goecho "Arguments to the functions were $1, $2, ..."}

自动跳转:http://github.com/joelthelion/autojump/wiki使用此技术为您提供学习shell目录书签。

您可以使用.在当前shell环境中执行脚本:

. script_name

或者,它更易读但特定于shell的别名source

source script_name

这避免了子shell,并允许任何变量或内置项(包括cd)影响当前shell。

最后使用exec bash

bash脚本在其当前环境或其当前环境上运行子级,但从不在其父级环境上。

然而,这个问题经常被问到,因为人们想要另一个目录中的bash脚本的执行后留在某个目录中的(新)bash提示符处

如果是这种情况,只需在脚本末尾执行子bash实例

#!/usr/bin/env bashcd /home/tree/projects/javaecho -e '\nHit [Ctrl]+[D] to exit this child shell.'exec bash

要返回到前面的父实例bash,请使用Ctrl+D

更新

至少对于较新版本的bash,最后一行的exec不再需要。此外,可以通过使用$SHELL环境变量使脚本与任何首选shell一起使用。然后给出:

#!/usr/bin/env bashcd desired/directoryecho -e '\nHit [Ctrl]+[D] to exit this child shell.'$SHELL

您可以在.bash_profile中创建如下函数,它将顺利工作。

以下函数接受一个可选参数,该参数是一个项目。例如,您可以运行

cdproj

cdproj project_name

这是函数定义。

cdproj(){dir=/Users/yourname/projectsif [ "$1" ]; thencd "${dir}/${1}"elsecd "${dir}"fi}

不要忘记你的来源.bash_profile

您不需要脚本,只需设置正确的选项并创建一个环境变量。

shopt -s cdable_vars

在你的~/.bashrc中允许cd到环境变量的内容。

创建这样一个环境变量:

export myjava="/home/tree/projects/java"

您可以使用:

cd myjava

其他替代品

只需运行:

cd /home/xxx/yyy && command_you_want

正如其他答案所解释的,您已经更改了目录,但仅限于运行脚本的子shell.这不会影响父shell。

一种解决方案是使用bash函数而不是bash脚本(sh);通过将您的bash脚本代码放入函数中。这使得函数可以作为命令使用,然后,这将在没有子进程的情况下执行,因此任何cd命令都会影响调用者shell。

Bash函数:

bash配置文件的一个特性是存储可以在终端或bash脚本中运行的自定义函数,就像运行应用程序/命令一样,这也可以用作长命令的快捷方式。

为了使您的功能高效系统广泛您将需要复制您的功能在几个文件的末尾

/home/user/.bashrc/home/user/.bash_profile/root/.bashrc/root/.bash_profile

您可以sudo kwrite /home/user/.bashrc /home/user/.bash_profile /root/.bashrc /root/.bash_profile快速编辑/创建这些文件

如何:

将bash脚本代码复制到bash配置文件末尾的新函数中并重新启动终端,然后您可以运行cdd或您编写的任何函数。

脚本示例

使用cdd创建cd ..的快捷方式

cdd() {cd ..}

ls快捷方式

ll() {ls -l -h}

ls快捷方式

lll() {ls -l -h -a}

这应该符合您的要求。更改到感兴趣的目录(从脚本中),然后生成一个新的bash shell。

#!/bin/bash
# saved as mov_dir.shcd ~/mt/v3/rt_linux-rt-tools/bash

如果你运行这个,它会带你到感兴趣的目录,当你退出它时,它会带你回到原来的地方。

root@intel-corei7-64:~# ./mov_dir.sh
root@intel-corei7-64:~/mt/v3/rt_linux-rt-tools# exitroot@intel-corei7-64:~#

这甚至会带你回到原来的目录,当你退出(CTRL+d

注意讨论如何设置父进程的工作目录?

它包含一些hackish答案,例如。https://stackoverflow.com/a/2375174/755804(通过gdb更改父进程目录,不要这样做)和https://stackoverflow.com/a/51985735/755804(命令tailcdcd文件名注入父进程的输入流;理想情况下,它应该是bash的一部分而不是hack)

这是一个古老的问题,但我真的很惊讶我没有看到这个技巧

而不是使用cd,您可以使用

export PWD=the/path/you/want

无需创建子shell或使用别名。

请注意,您有责任确保/path/你/想要的存在。

我必须在tcsh中工作,我知道这不是一个优雅的解决方案,但例如,如果我必须将文件夹更改为一个单词不同的路径,整个事情都可以在别名中完成

a alias_name 'set a = `pwd`; set b = `echo $a | replace "Trees" "Tests"` ; cd $b'

如果路径总是固定的,则

a alias_name2 'cd path/you/always/need'

应该可以在上面的行中,新文件夹路径设置为

这将Serge的回答大卫无关的回答结合在一起。它会更改目录,然后不是强制使用bash shell,而是启动用户的默认shell。然而,它需要getent/etc/passwd来检测默认shell。

#!/usr/bin/env bashcd desired/directoryUSER_SHELL=$(getent passwd <USER> | cut -d : -f 7)$USER_SHELL

当然,这仍然存在创建嵌套shell的相同缺陷。

而不是将脚本文件和cd执行到某个文件夹,

我们可以通过:

  • source.某些外壳脚本
  • alias cd命令
  • 定义一个函数ant cd到文件夹

例子:

. script# orsource script
alias ghqc='cd $(ghq root)/$(ghq list | fzf)'
ghqc() {cd $(ghq root)/$1}