关于linux:为什么“cd”不能在shell脚本中运行?

您所在的位置:网站首页 mkg是什么 关于linux:为什么“cd”不能在shell脚本中运行?

关于linux:为什么“cd”不能在shell脚本中运行?

#关于linux:为什么“cd”不能在shell脚本中运行? | 来源: 网络整理| 查看: 265

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

12#!/bin/bash cd /home/tree/projects/java

我将这个文件保存为proj,添加了chmod的执行权限,并复制到/usr/bin中。当我叫它的时候:proj什么都不做。我做错什么了?

相关讨论 跨站点复制:superuser.com/questions/176783/… 在将来,您可以尝试在最后一行使用pwd测试它。所以在脚本完成之前,您可以检查它是否工作。 @莱斯曼那是怎么复制的? @aland因为op实际上不运行脚本,所以工作目录对他没有改变。cd命令在脚本内部工作良好,请自己尝试。 为什么CD不是程序?,cd在哪里?

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

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

1alias proj="cd /home/tree/projects/java" 相关讨论 别名位于~/.bash_profile和/或~/.bashrc中 别名在管理或更改方面不太灵活。如果有很多CD,脚本可能会更好。 函数比别名更灵活,所以当别名不够时,您接下来会看到这个问题。 我认为这次讨论毫无意义。"有无数种方法可以用Perl(tm)制作东西。 +1为优秀的解释,再加上一个有用的替代方案! 值得注意的是,在MS-DOS上,脚本的行为是被调用的脚本可以更改调用命令shell的目录(甚至驱动器)?那个Unix没有这个缺陷吗? 乔纳森:虽然这是真的,但它与这个问题并不真正相关。如果每个人都列出MS-DOS中相应的缺陷,那么答案的长度将是原来的两倍! S/缺陷/副作用/;S/值得注意/不;。/ @federicoa.ramponi或in ~/.bash_别名 另一种解决方法是源代码脚本文件:. my-script或source my-script。

你没做错什么!您已经更改了目录,但只在运行脚本的子shell中。

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

1. proj

但我更喜欢格雷格的建议,在这个简单的例子中使用别名。

相关讨论 .也拼写为source,选择你觉得更难忘的。 @短暂:解释其工作原因的好点源代码也证明了懒惰而不是必要性常常是发明源代码的根源。 @ephemient:注意源代码用于C shell和bash;它在posix或korn shell中不受支持,在经典的bourne shell中也不受支持。 "source"用于z-shell @内森莫斯两个都工作。 @Adamilss它工作得很好,但是有一个缺点-不知何故source/dot命令禁用了使用tab键自动完成脚本/命令名称的可能性。仍然可以使用tab键添加参数/输入,但不幸的是,需要直接输入命令名。你知道在这种情况下如何使tab键工作吗? @Rafal我在我的系统上测试了这个(在油灰终端上)。我能够用制表符完成命令名,对于点和"source"都没有问题。可能是你的环境? @斯图尔特,你说得对。我刚在Ubuntu14.04上测试过这个,标签完成工作很好。这肯定是2014年1月Ubuntu 13.10的问题,或者是我的配置问题。谢谢你的信息。

脚本中的cd在技术上起作用,因为它改变了运行脚本的shell的目录,但这是从交互shell派生出来的独立过程。

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

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

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

相关讨论 我同意,这是最好的答案。另外,别名在某些情况下可能是合适的,但是如果他试图在脚本中使用CD,并且想向其中添加任何其他内容,那么别名将是无用的。 这看起来是个解决方案!我正在尝试实现它,但它没有执行:(这是我的脚本:!/bin/bash jhome()echo"请"cd/home echo"工作"jhome @Gantman,你应该把它添加到"shell启动文件"中,比如~/.bashrc。 如果在文件中,您需要使用. filename或source filename,以便当前shell看到它,而不是运行命令的子shell。或者接受杰基的建议,把它放在类似于~/.bashrc的地方。 你也可以使用一个论点(或两个…),即:jhome(){ cd /home/tree/projects/$1; }。 这应该是正确的方式,这使得使用特殊字符成为可能,例如"-"。 完美,完美地解决了我的问题。这应该是有正确答案的标记。

cd是在脚本的外壳中完成的。当脚本结束时,该shell将退出,然后您将留在原来的目录中。"source"脚本,不要运行它。而不是:

1./myscript.sh

1. ./myscript.sh

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

相关讨论 这很酷,可能很好知道。后者到底做了什么(它是如何工作的)?这可能是这个线程上最好的解决方案。 FWIW,在亚当·利斯的回答的评论部分,短暂地回答了"是什么"的问题。它和source是一样的。 小心,"源头"是一种羞怯。即dash(debian-default for/bin/sh)不支持它,而"."按预期工作。 伟大的回答!另外,如果myscript.sh在$path中包含的目录中,您可以从任何地方获取它,而无需指定完整路径。

要制作一个bash脚本,该脚本将CD到一个选择目录:

创建脚本文件

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

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

1234#!/bin/sh # file /scripts/mastercode.sh # alias cdjava='. /scripts/cdjava' 我创建了一个启动文件,在其中转储所有别名和自定义函数。 然后我将这个文件源到我的.bashrc中,以便在每次启动时设置它。

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

然后在.bashrc文件的末尾:

1source /scripts/mastercode.sh

现在它很容易CD到你的Java目录,只需键入CDJava,你就在那里。

相关讨论 文件mastercode.sh不需要shabang(#!/bin/sh),因为它不是(也不能)在子shell中执行。但同时,您也需要记录这个文件的外壳"风格";例如,ksh或bash(或(t)csh/zsh等),它几乎肯定不是sh。我通常会添加一条注释(但不是shebang)来传达这一点;例如,"这个文件的来源(来自bash),而不是作为shell脚本运行。" 另一个技巧(对于bash):如果在脚本中使用变量,那么当脚本是sourced(通过alias时),这些变量将泄漏到shell环境中。要避免这种情况,请在函数中完成脚本的所有工作,并在脚本末尾调用它。在函数中,声明任何变量local。 在Ubuntu中,只需创建~/.bash_别名(如果它还不存在的话)。然后只需在那里添加别名,重新启动终端并完成操作。

杰里米·鲁滕使用符号链接的想法引发了一种想法,这种想法并没有越过任何其他答案。用途:

1CDPATH=:$HOME/projects

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

1cd java

而且,如果在当前目录中没有Java目录,那么它将直接带到$home /jpjs/java-没有别名,没有脚本,没有可疑的执行器或点命令。

我的$home是/users/jleverer;我的$cdpath是:

1:/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

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

1. script_name

或者,它更易读但外壳特定的别名source:

1source script_name

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

我通过使用OCX1(2)获得了我的代码

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

这是我的节目单

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

这是我的终点站

1234nova:~ Kael$ nova:~ Kael$ . workspace.sh Taking you to eclipe's workspace. nova:workspace Kael$ 相关讨论 . something和./something有什么区别?这个答案对我有用,我不明白为什么。 . something允许您从任何位置运行脚本,./something要求您位于存储文件的目录中。 @dracorat stackoverflow.com/questions/13786499/…

最后使用exec bash。

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

然而,这个问题经常会被问到,因为在从另一个目录执行bash脚本之后,您希望留在某个目录中的bash提示符下。

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

123#!/usr/bin/env bash cd /home/tree/projects/java exec bash 相关讨论 这将创建一个新的子外壳。当您键入exit时,您将返回运行此脚本的shell。

简单运行:

1cd /home/xxx/yyy && command_you_want 相关讨论 这对我很有用谢谢@warhansen

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

您可以执行以下操作:

1234#!/bin/bash cd /your/project/directory # start another shell and replacing the current exec /bin/bash

编辑:这也可以是"点式的",以防止创建后续的shell。

例子:

1. ./previous_script  (with or without the first line) 相关讨论 跑了几次后,情况变得相当混乱。例如,您必须多次使用exit(或ctrl+d)退出shell。别名要干净得多(即使shell命令输出一个目录,而且它是CD到输出的——alias something="cd getnewdirectory.sh) 注意"执行"。它取代了旧外壳。 exec只替换运行cd命令的子shell,而不是运行脚本的shell。如果你在剧本上画点线,那你就对了。 把它弄成点状-没问题。我刚提出解决方案。这不取决于你如何启动它。 呵呵,我想最好只用cd命令"点"一行脚本:)我还是保留我的答案…那将是正确的愚蠢的回答错误的愚蠢的问题:) stackoverflow.com/questions/874452/…是我建议的用于启动dev env的交互式用法。 exec/bin/bash做了我需要的。谢谢!

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

1

$ nano ~./bashrc

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

2

$ source ~/.bashrc

3

$ switchp java

直接实现:CD/home/树/项目/ Java

希望有帮助!

相关讨论 @w m.您最终可以在没有任何参数的情况下执行"$switchp",直接转到项目树。 @WorkDreamer您上面描述的函数方法解决了在进入子文件夹时的一些问题,这些子文件夹在我的系统中具有相同的父文件夹。谢谢您。

您可以组合别名和脚本,

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

前提是该脚本响应目标路径。请注意,这些是围绕脚本名称的背景。

例如,您的脚本可以是

12#!/bin/bash echo /home/askgelal/projects/java/$1

这种技术的优势在于,脚本可以接受任意数量的命令行参数,并通过可能复杂的逻辑计算出不同的目标。

相关讨论 为什么?你可以只使用:proj() { cd"/home/user/projects/java/$1"; }=>proj"foo"(或者,proj"foo bar"proj() { cd"/home/user/projects/java/$1"; shift; for d; do cd"$d"; done; }=>proj a b c=>将cd转换成/home/user/projects/java/a/b/c

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

您可能希望改用符号链接。它允许您对一个文件或目录进行"快捷方式",因此您只需要键入类似于cd my-project的内容。

相关讨论 在每个目录中都有这个符号链接会很麻烦。可以将symlink放在$home中,然后执行'cd~/my project'。不过,坦率地说,使用cdpath更简单。

为了快速浏览目录,有$cdpath、cdargs和自动生成别名的方法

http://jackndempsey.blogspot.com/2008/07/cdargs.html

网址:http://muness.blogspot.com/2008/06/lazy-bash-cd-aliaes.html

https://web.archive.org/web/1/http://articles.technrepublic%2ecom%2ecom/5100-10878_11-5827311.html

您可以将Adam&Greg的别名和点方法结合起来,使之更具动态性。-

1alias project=". project"

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

在~/.bash_配置文件中。添加下一个函数

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

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

1move_me

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

您可以使用运算符;;:

CD我的目录

相关讨论 投反对票:这并不试图回答实际问题。您可以在提示下运行两个命令(如果您希望第二个命令以第一个命令为条件,或者仅以;或它们之间的换行符为条件),但将其放入脚本将使您返回到"当cd实际成功时,父shell为什么不使用新目录?"

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

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

如果您运行这个,它将把您带到感兴趣的目录,当您退出它时,它将把您带回到原始位置。

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

当您退出时,这甚至会使您返回到原始目录(ctrl+d)

相关讨论 生成一个新的bash意味着你将失去你的历史,它将重新开始。

虽然寻源您要运行的脚本是一种解决方案,但您应该知道,然后该脚本可以直接修改当前shell的环境。而且,不可能再传递参数了。

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

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

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

很长一段时间之后,但我做了以下事情:

创建一个名为case的文件

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

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

保存它,然后:

1chmod +x case

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

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

现在,当我键入:

1case 12345

基本上我在打字:

1cd /home/12345

您可以在"case"后键入任何文件夹:

12345case 12 case 15 case 17

就像打字:

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

分别地

在我的例子中,路径要长得多——这些人用前面的信息总结了这一点。

相关讨论 别名中的cd是多余的、不雅的;别名应该是简单的。~/case`代替。另外,case是一个保留的关键字,因此对于一个名称来说,这是一个相当糟糕的选择。

你可以在你的.bash_profile中创建一个类似下面的函数,它将顺利工作。

以下函数接受项目的可选参数。例如,您可以运行

1cdproj

1cdproj project_name

这是函数定义。

12345678cdproj(){     dir=/Users/yourname/projects     if ["$1" ]; then       cd"${dir}/${1}"     else       cd"${dir}"     fi }

别忘了找到你的.bash_profile

相关讨论 答案比别名好得多

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

1alias p='. p'

在你的BASHC中

相关讨论 这是做什么的?它看起来像是递归地运行自己,不过我敢肯定您是否在它不运行之前运行过它;)

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

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

如果您使用fish作为外壳,最好的解决方案是创建一个函数。例如,对于原始问题,可以复制下面的4行并将它们粘贴到fish命令行中:

1234function proj    cd /home/tree/projects/java end funcsave proj

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

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

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

并输入文本:

123function proj    cd /home/tree/projects/java end

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

(注意:使用funcsave的第一个方法为您创建proj.fish文件)。

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

1shopt -s cdable_vars

在您的~/.bashrc中,允许cd输入环境变量的内容。

创建这样的环境变量:

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

你可以使用:

1cd myjava

其他替代方案。

使用bash profile函数:

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

为了使您的功能更加高效,您需要在多个文件的末尾复制您的功能。

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

您可以使用ecx1〔5〕快速编辑/创建这些文件

脚本示例

用cdd快捷到cd ..。

123cdd() {   cd .. }

LS快捷方式

123ll() {   ls -l -h }

LS快捷方式

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

Howto:

在文件末尾复制您的函数并重新启动终端,然后您可以运行cdd或您编写的任何函数。

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

12cd somedir; \ pwd


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3