为什么"cd"不能在shell脚本中工作?

ash*_*lal 735 linux shell

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

#!/bin/bash
cd /home/tree/projects/java
Run Code Online (Sandbox Code Playgroud)

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

Gre*_*ill 613

Shell脚本在子shell中运行,每个子shell都有自己的当前目录概念.的cd成功,但只要子shell退出,你回来在交互式shell和从来都没有改变,因此.

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

alias proj="cd /home/tree/projects/java"
Run Code Online (Sandbox Code Playgroud)

  • 别名在〜/ .bash_profile和/或〜/ .bashrc中 (77认同)
  • 乔纳森:虽然这是真的,但这与问题无关.如果必须每个列出MS-DOS中相应的缺陷,SO上的答案会得到两倍的时间! (21认同)
  • 解决它的另一种方法是获取脚本文件:`.my-script`或`source my-script`. (16认同)
  • 函数比别名更灵活,因此当别名不够时,您可以在下一步查看. (15认同)
  • 别名管理或更改的灵活性不高.如果有很多'cd',脚本可能会更好. (7认同)
  • 值得注意的是,在MS-DOS上,脚本的行为是被调用的脚本可以更改调用命令shell的目录(甚至是驱动器)吗?那个Unix没有这个缺陷? (3认同)
  • s /缺陷/副作用/; s /值得注意/不&/ (3认同)
  • @ FedericoA.Ramponi或〜/ .bash_aliases (2认同)

Ada*_*iss 484

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

您可以使用"dot"命令在当前进程中运行脚本:

. proj
Run Code Online (Sandbox Code Playgroud)

但是我更喜欢Greg建议在这个简单的例子中使用别名.

  • `.`也拼写为`source`,选择你觉得更难忘的. (89认同)
  • @Ephemient:好点源解释为什么它的工作源也证明了懒惰 - 不是必需品 - 往往是发明源的母亲 (46认同)
  • @ephemient:注意源是在C shell和Bash中使用的; 它在POSIX或Korn shell中不受支持,在经典的Bourne shell中也不受支持. (8认同)
  • "source"用于Z-shell (2认同)

Dig*_*oss 213

cd脚本中的技术工作,因为它改变了运行脚本的外壳的目录,但是这是从你的交互shell分叉一个单独的进程.

与Posix兼容的解决此问题的方法是定义shell过程而不是shell调用的命令脚本.

jhome () {
  cd /home/tree/projects/java
}
Run Code Online (Sandbox Code Playgroud)

您可以在其中输入或将其放入各种shell启动文件中.

  • 我同意,这是最好的答案,碰到了.此外,别名在某些情况下可能是合适的,但如果他试图在脚本中使用cd并想要向其添加任何其他内容,则别名将毫无用处. (5认同)
  • 这看起来像一个解决方案!而我正在尝试实现它,但它没有执行:(这是我的脚本:#!/ bin/bash jhome(){echo"please"cd/home echo"work"} jhome (3认同)
  • @GantMan,你应该将其添加到“shell启动文件”中,例如〜/.bashrc (3认同)
  • 你也可以使用一个参数(或两个......),即:`jhome(){cd/home/tree/projects/$ 1; }` (3认同)

小智 149

cd是在脚本的shell中完成的.当脚本结束时,该shell退出,然后您将保留在您所在的目录中."源"脚本,不要运行它.代替:

./myscript.sh
Run Code Online (Sandbox Code Playgroud)

. ./myscript.sh
Run Code Online (Sandbox Code Playgroud)

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

  • 这很酷,可能很有用.后者究竟做了什么(它是如何工作的)?这可能是此主题的最佳解决方案. (2认同)
  • fwiw,在Adam Liss回答的评论部分,ephemient回答了'.'的问题.是.它与`source`是一回事 (2认同)

小智 95

要创建一个将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就可以了.

  • 文件`mastercode.sh`不需要shabang(`#!/ bin/sh`),因为它不是(也不能)在子shell中执行.但与此同时,您需要记录此文件的shell"风味"; 例如,ksh或bash(或(t)csh/zsh等),它几乎肯定不是"sh".我通常会添加评论(但不是shebang)来传达此信息; 例如,_"这个文件应该来源(来自bash),而不是作为shell脚本运行."_ (2认同)

小智 46

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

. script_name
Run Code Online (Sandbox Code Playgroud)

或者,它更具可读性但特定于shell的别名source:

source script_name
Run Code Online (Sandbox Code Playgroud)

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


Jon*_*ler 37

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

CDPATH=:$HOME/projects
Run Code Online (Sandbox Code Playgroud)

前导结肠很重要; 这意味着如果当前目录中有一个目录'dir',那么' cd dir'将更改为该目录,而不是在其他地方跳转.如图所示设置值,您可以:

cd java
Run Code Online (Sandbox Code Playgroud)

并且,如果当前目录中没有名为java的子目录,那么它将直接转到$ HOME/projects/java - 没有别名,没有脚本,没有可疑的exec或点命令.

我的$ 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
Run Code Online (Sandbox Code Playgroud)


小智 25

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

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

这是我的计划

#!/bin/bash 
echo "Taking you to eclipse's workspace."
cd /Developer/Java/workspace
Run Code Online (Sandbox Code Playgroud)

这是我的终端

nova:~ Kael$ 
nova:~ Kael$ . workspace.sh
Taking you to eclipe's workspace.
nova:workspace Kael$ 
Run Code Online (Sandbox Code Playgroud)

  • `之间有什么区别?某事`和`./ something` ?? 这个答案对我有用,我不明白为什么. (2认同)

Ser*_*ndt 24

使用exec bash

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

但是,这个问题经常被问到,因为在从另一个目录执行bash脚本之后,想要在某个目录中保留bash提示符.

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

#!/usr/bin/env bash
cd /home/tree/projects/java
exec bash
Run Code Online (Sandbox Code Playgroud)

  • 这将创建一个新的子shell.当您键入`exit`时,您将返回运行此脚本的shell. (14认同)

war*_*sen 18

只需运行:

cd /home/xxx/yyy && command_you_want
Run Code Online (Sandbox Code Playgroud)


Dan*_*wak 12

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


wor*_*mer 10

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

1 -

$ nano~./bashrc

 function switchp
 {
    cd /home/tree/projects/$1
 }
Run Code Online (Sandbox Code Playgroud)

2-

$ source~/.bashrc

3 -

$ switchp java

它会直接执行:cd/home/tree/projects/java

希望有所帮助!

  • @workdreamer 您上面描述的函数方法在这里解决了进入在我的系统中具有相同父文件夹的子文件夹的一些麻烦。谢谢你。 (2认同)

The*_*evs 9

你可以这样做:

#!/bin/bash
cd /your/project/directory
# start another shell and replacing the current
exec /bin/bash
Run Code Online (Sandbox Code Playgroud)

编辑:这也可以"点缀",以防止后续shell的创建.

例:

. ./previous_script  (with or without the first line)
Run Code Online (Sandbox Code Playgroud)

  • exec只替换运行cd命令的子shell,而不是运行脚本的shell.如果你点缀了剧本,那你就是对的. (2认同)
  • 呵呵,我觉得最好只用cd命令'点'单行脚本:)我还是会保留我的答案......这对于错误的愚蠢问题是正确的愚蠢答案:) (2认同)

Jer*_*ten 7

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

您可能希望使用符号链接.它允许您创建文件或目录的"快捷方式",因此您只需输入类似的内容cd my-project.


J. *_*ett 7

您可以组合别名和脚本,

alias proj="cd \`/usr/bin/proj !*\`"
Run Code Online (Sandbox Code Playgroud)

只要脚本回显目标路径.请注意,这些是围绕脚本名称的反引号. 

例如,您的脚本可能是

#!/bin/bash
echo /home/askgelal/projects/java/$1
Run Code Online (Sandbox Code Playgroud)

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

  • 为什么?你可以使用:`proj(){cd"/ home/user/projects/java/$ 1"; }`=>`proj"foo"`(或者,'proj"foo bar"`<=如果你有空格)......或者甚至(例如):`proj(){cd"/ home/user /项目/ JAVA/$ 1" ; 转移; 为d; 做cd"$ d"; 完成; }`=>`proj abc` =>将`cd`变成`/ home/user/projects/java/a/b/c` (3认同)

rob*_*ach 6

您可以结合使用Adam&Greg的别名和点式方法来制作更具动感的内容 -

alias project=". project"
Run Code Online (Sandbox Code Playgroud)

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


mih*_*bea 5

在您的〜/ .bash_profile文件中。添加下一个功能

move_me() {
    cd ~/path/to/dest
}
Run Code Online (Sandbox Code Playgroud)

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

move_me 
Run Code Online (Sandbox Code Playgroud)

然后您将被移至目标文件夹。