天道酬勤,学无止境

Run bash script as source without source command

Is there any way to mark a script to be "run as source" so you don't have to add the source or "." command to it every time? i.e., if I write a script called "sup", I'd like to call it as

sup Argument

rather than

source sup Argument

or

. sup Argument

Basically, I'm trying to use cd within a script.

标签

评论

Bash forks and starts a subshell way before it or your kernel even considers what it's supposed to do in there. It's not something you can "undo". So no, it's impossible.

Thankfully.

Look into bash functions instead:

sup() {
    ...
}

Put that in your ~/.bashrc.

When you are running a shell, there are two ways to invoke a shell script:

  • Executing a script spawns a new process inside which the script is running. This is done by typing the script name, if it is made executable and starts with a

    #!/bin/bash
    line, or directly invoking
    /bin/bash mycmd.sh
  • Sourcing a script runs it inside its parent shell (i.e. the one you are typing commands into). This is done by typing

    source mycmd.sh
    or
    . mycmd.sh

So the cd inside a shell script that isn't sourced is never going to propagate to its parent shell, as this would violate process isolation.

If the cd is all you are interested about, you can get rid of the script by using cd "shortcuts"... Take a look into the bash doc, at the CDPATH env var.

Otherwise, you can use an alias to be able to type a single command, instead of source or .:

alias mycmd="source mycmd.sh"

Create an alias for it:

alias sup=". ~/bin/sup"

Or along those lines.

See also: Why doesn't cd work in a bash shell script?


Answering comment by counter-example: experimentation with Korn Shell on Solaris 10 shows that I can do:

$ pwd
/work1/jleffler
$ echo "cd /work5/atria" > $HOME/bin/yyy
$ alias yyy=". ~/bin/yyy"
$ yyy
$ pwd
/work5/atria
$

Experimentation with Bash (3.00.16) on Solaris 10 also shows the same behaviour.


It is not possible to source a script in your current environment if you sub-shell the script at invoke.

However, you can check that script is sourced and force the script to terminate if not:

if [ -z "$PS1" ] ; then
    echo "This script must be sourced. Use \"source <script>\" instead."
    exit
fi

The same way, you can force a script not to be sourced but to be sub-shelled instead (preserve current shell environment):

if [ "$PS1" ] ; then
    echo "This script cannot be sourced. Use \"./<script>\" instead."
    return
fi

Both versions are available as gists: see please source and don't source.

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 确定是否执行了shell脚本“采购”它(Determining whether shell script was executed “sourcing” it)
    问题 Shell脚本是否可以测试它是否通过source执行? 也就是说,例如 $ source myscript.sh $ ./myscript.sh myscript.sh可以与这些不同的Shell环境区分开吗? 回答1 我认为,Sam想要做的事可能是不可能的。 半衰变的解决方案在多大程度上可以实现,取决于... ...用户的默认外壳,以及 ...允许使用哪些替代外壳。 如果我正确理解了Sam的要求,他想拥有一个“脚本” myscript ,即... ...不能通过调用其名称为myscript (即具有chmod ax )直接执行; ...通过调用sh myscript或bash myscript对于用户不是间接可执行的 ...仅在通过以下方式调用时运行其包含的功能和命令: . myscript . myscript 首先要考虑的是这些 直接通过脚本名称( myscript )调用脚本需要脚本中的第一行,如#!/bin/bash或类似名称。 这将直接确定将调用bash可执行文件(或symlink)的已安装实例来运行脚本的内容。 这将是一个新的shell过程。 它要求脚本文件本身具有可执行标志集。 通过调用以脚本的(path +)名称作为参数( sh myscript )的shell二进制文件来运行脚本与“ 1”相同。 -除了不需要设置可执行标志
  • 如何在不使用“ sh”或“ bash”命令的情况下运行shell脚本?(How do I run a shell script without using “sh” or “bash” commands?)
    问题 我有一个要运行的shell脚本,而无需使用“ sh”或“ bash”命令。 例如: 代替: sh script.sh 我想使用: script.sh 我怎样才能做到这一点? PS(i)我不太使用shell脚本,并且尝试阅读有关别名的信息,但是我不了解如何使用它们。 (ii)我还阅读了有关将脚本与PATH变量中的另一个文件链接的信息。 我正在使用大学服务器,但没有在这些位置创建文件的权限。 回答1 在文件顶部添加“ shebang”: #!/bin/bash 并使您的文件可执行( chmod +x script.sh )。 最后,修改路径以添加脚本所在的目录: export PATH=$PATH:/appropriate/directory (通常,您要使用$HOME/bin来存储自己的脚本) 回答2 这些是直接使用脚本名称的先决条件: 在最顶部添加shebang行( #!/bin/bash )。 使用chmod u+x scriptname脚本名使脚本可执行(其中scriptname是脚本的名称)。 将脚本放在/usr/local/bin文件夹下。 注意:我建议将其放在/usr/local/bin因为该路径很可能已经添加到了PATH变量中。 仅使用脚本名称scriptname运行脚本。 如果您无权访问/usr/local/bin请执行以下操作: 在您的主目录中创建一个文件夹
  • Plink 在连接时不提供 bashrc 或 bash_profile(Plink does not source bashrc or bash_profile on connect)
    问题 我试图在 Windows 上使用 plink 作为 ssh 替代方案,但我发现当 plink 连接到远程 linux 机器时,它不会提供 .bash_profile 或 .bashrc。 我应该创建一个不同的点文件吗? 或者还有其他选择吗? 例如,我的 bashrc 文件在我的路径中添加了一个目录。 这个目录包含我想使用的额外程序,一个是 python。 这将不起作用: plink host python 这将在哪里: plink host "source .bashrc;python" 当我在没有命令参数的情况下使用 plink 时,它会获取 .bash_profile 并且一切正常,但似乎仅通过发送命令 plink 不会获取任何文件。 有解决方法吗? 回答1 如果您只是通过 ssh 或 plink 连接到远程主机,它将启动登录帐户的默认 shell。 如果该 shell 是 bash,bash 将自动获取 .bash_profile。 如果您通过 ssh 或 plink 连接到远程主机要求执行命令,ssh 将尝试仅执行该命令。 您可以通过使用ForcedCommand来实现您想要实现的目标。 另见此处: https://serverfault.com/questions/162018/force-ssh-to-use-a-specific-shell/166129
  • 如何执行一个py文件_如何让shell脚本变成可执行文件
    在本教程中介绍创建bash脚本并使用chmod命令使脚本可执行,无需脚本前面加上sh或bash命令就可以运行它。 创建脚本文件 第一步是使用以下命令创建一个扩展名为.sh的新文件: [root@localhost ~]# touch hello_script.sh 写一个简单的脚本 使用vim编辑器打开新创建的文件,将以下bash脚本添加到文件中: [root@localhost ~]# vim hello_script.sh 下面是添加到文件中的脚本内容: #!/bin/bash echo "Hello World" 编辑完,保存并退出。 执行Bash脚本 有两种方法可以运行bash文件。第一种是通过使用bash或sh命令。另一种将文件添加可执行权限,就可以直接运行。让我们运行以下命令以使用bash或sh命令执行bash脚本。 [root@localhost ~]# sh hello_script.sh Hello World[root@localhost ~]# bash hello_script.sh Hello World 为脚本文件设置可执行权限 执行bash脚本的第二种方法是设置可执行权限。 [root@localhost ~]# chmod +x hello_script.sh 可以看到hello_script.sh文件已经有x可执行权限了。 执行脚本
  • 如何重新加载.bashrc设置而不注销并重新登录?(How to reload .bashrc settings without logging out and back in again?)
    问题 如果我对.bashrc进行了更改,如何在不注销并重新登录的情况下重新加载它? 回答1 您可以输入长格式命令: source ~/.bashrc 或者您可以使用命令的较短版本: . ~/.bashrc 回答2 或者您可以使用: exec bash 这做同样的事情,并且更容易记住(至少对我而言)。 exec命令通过运行指定的命令行来完全替换shell进程。 在我们的示例中,它用bash的新实例(使用更新的配置文件)替换了当前shell的内容。 回答3 为了补充和对比两个最受欢迎的答案,。 〜/ .bashrc和exec bash: 两种解决方案都有效地重新加载~/.bashrc ,但是有一些区别: . ~/.bashrc . ~/.bashrc或source ~/.bashrc将保留您当前的shell : 除了将~/.bashrc重新加载到当前外壳程序( sourcing )中所做的修改之外,当前外壳程序及其状态均得以保留,其中包括环境变量,外壳程序变量,外壳程序选项,外壳函数和命令历史记录。 exec bash或更确切地说是exec "$BASH" [1] ,将用一个新实例替换您当前的shell ,因此仅保留您当前shell的环境变量(包括您自定义的变量)。 换句话说:就外壳变量,外壳函数,外壳选项,命令历史记录而言,对当前外壳的任何临时更改都将丢失。 根据您的需求
  • How can I create a generic shell command to exit or return from a script that is either executed or sourced?
    I am trying to implement a single command that I assume would be a wrapper for the normal 'exit' and 'return' shell builtins that come with Bash (Bourne, et al), a command that is not plagued by the incompatibility issues of these in that if I use 'exit 1' to end a script with error level 1, if I source that script it will cause the shell I am in to terminate. Likewise, if I use return, it has the problems that: a) It will only return to the calling function, not end the whole script being run without additional logic. b) If I use return in the main script and execute it, it will error rather
  • 从cronjob运行bash脚本失败,并显示“无此文件或目录”(Running a bash script from a cronjob fails with “No such file or directory”)
    问题 我正在尝试运行以下bash脚本,该脚本在激活conda环境后运行Python程序。 send.bash #!/bin/bash source activate manage_oam_users python ~/path/to/script/send.py source deactivate crontab 30 * * * * source /path/to/script/send.bash 我从cron收到以下错误,尽管运行source send.bash可以正常工作。 我也尝试过使用bash send.bash ,在手动运行时可以正常工作,但是从cron运行时会导致相同的错误。 /path/to/script/send.bash: line 2: activate: No such file or directory 回答1 activate和deactivate可能是脚本位于$PATH变量中的某个条目所指向的位置。 通常,为一个用户在本地安装的软件会将语句添加到.profile文件或.bashrc ,这些语句扩展了$PATH变量,以便您可以使用软件的脚本而无需使用完整路径。 当您的bash自动加载.profile和.bashrc ,CRON不会这样做。 至少有两种解决方案。 A)无处不在 您可以在CRON作业执行的脚本中使用完整路径,如下所示: #!/bin/bash
  • 如何创建通用 shell 命令以退出或从已执行或获取的脚本返回?(How can I create a generic shell command to exit or return from a script that is either executed or sourced?)
    问题
  • shell脚本的编写及运行
    shell脚本的编写及运行 1. which命令和/etc/shells文件2. 输出hello shell的脚本2.1 脚本的编写2.2 脚本的运行 3. 接收用户的输入数据4. 运行shell脚本的方式详解4.1 在新进程中运行shell脚本4.2 在当前进程中运行shell脚本 1. which命令和/etc/shells文件 which命令的功能: which命令用于查找并显示给定命令的绝对路径, 环境变量$ PATH中保存了查找命令时需要遍历的目录。 which指令会在环境变量$PATH设置的目录里查找符合条件的文件。 使用which命令,就可以看到某个系统命令是否存在,以及执行的到底是哪一个位置的命令。 /etc/shells文件: /etc/shells文件是一个有效登陆shell的列表,可以查看可以使用的shell解释器,在登陆shell时,会查询这个文件。 2. 输出hello shell的脚本 2.1 脚本的编写 vim 01.sh #编写一个脚本(文件名必须以.sh结尾) 脚本内容: #!/bin/bash #指定shell程序的解释器 echo "hello shell!" #这是一条输出语句 2.2 脚本的运行 运行方式不只有单一的一种,以下四种方式都可以用来执行shell脚本,根据个人不同的习惯来使用。 sh 01.sh . 01.sh source
  • 如何在Bash脚本中激活virtualenv源(How to source virtualenv activate in a Bash script)
    问题 如何创建Bash脚本来激活Python virtualenv? 我有一个类似的目录结构: .env bin activate ...other virtualenv files... src shell.sh ...my code... 我可以通过以下方式激活我的virtualenv: user@localhost:src$ . ../.env/bin/activate (.env)user@localhost:src$ 但是,从Bash脚本执行相同操作将不会执行以下操作: user@localhost:src$ cat shell.sh #!/bin/bash . ../.env/bin/activate user@localhost:src$ ./shell.sh user@localhost:src$ 我究竟做错了什么? 回答1 当您获取源代码时,就是将激活脚本加载到活动的shell中。 当您在脚本中执行此操作时,会将其加载到该外壳中,该外壳将在脚本完成后退出,并且您将返回到原始的未激活外壳。 最好的选择是在函数中执行此操作 activate () { . ../.env/bin/activate } 或别名 alias activate=". ../.env/bin/activate" 希望这可以帮助。 回答2 您应该使用source调用bash脚本。 这是一个例子:
  • 从Shell脚本导入函数(Importing functions from a shell script)
    问题 我有一个要使用shUnit测试的shell脚本。 该脚本(以及所有功能)都在一个文件中,因为它使安装更加容易。 script.sh示例 #!/bin/sh foo () { ... } bar () { ... } code 我想写第二个文件(不需要分发和安装)来测试script.sh定义的功能。 类似于run_tests.sh #!/bin/sh . script.sh # Unit tests 现在的问题出在. (或Bash中的source )。 它不仅解析函数定义,而且执行脚本中的代码。 由于没有参数的脚本没有任何坏处,我可以 . script.sh > /dev/null 2>&1 但是我在徘徊,是否有更好的方法可以实现自己的目标。 编辑 在源脚本调用exit的情况下,我建议的解决方法不起作用,因此我必须捕获退出 #!/bin/sh trap run_tests ERR EXIT run_tests() { ... } . script.sh 调用了run_tests函数,但是一旦我重定向了source命令的输出,脚本中的函数就不会被解析,并且在陷阱处理程序中不可用 这有效,但我得到script.sh的输出: #!/bin/sh trap run_tests ERR EXIT run_tests() { function_defined_in_script_sh }
  • linux 源命令在构建 Dockerfile 时不起作用(linux source command not working when building Dockerfile)
    问题 我有一个定义 Ruby on Rails 堆栈的 Dockerfile。 这是 Dockerfile: FROM ubuntu:14.04 MAINTAINER example <examplen@example.com> # Update RUN apt-get update # Install Ruby and Rails dependencies RUN apt-get install -y \ ruby \ ruby-dev \ build-essential \ libxml2-dev \ libxslt1-dev \ zlib1g-dev \ libsqlite3-dev \ nodejs \ curl RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 RUN curl -sSL https://get.rvm.io | bash -s stable --rails RUN /bin/bash -c "source /usr/local/rvm/scripts/rvm" # Install Rails RUN gem install rails # Create a new Rails app under /src/my-app
  • 您如何返回到源bash脚本?(How do you return to a sourced bash script?)
    问题 我在bash脚本中使用“ source”,如下所示: #!/bin/bash source someneatscriptthatendsprematurely.sh 我想退出prematurely.sh脚本的someneatscript,而不退出主脚本。 任何帮助表示赞赏! 回答1 您需要return语句: return [n] 使函数以n指定的返回值退出。 如果省略n ,则返回状态为函数体内执行的最后一条命令的返回状态。 如果在函数外部使用,但在脚本执行期间使用. (源)命令,它将使外壳程序停止执行该脚本,并返回n或脚本中最后执行的命令的退出状态作为脚本的退出状态。 如果在函数外部而不是在脚本执行期间使用. ,返回状态为false。 与RETURN陷阱关联的任何命令都将在函数或脚本之后恢复执行之前执行。 您可以通过以下两个脚本看到这一点: script1.sh: . script2.sh echo hello again script2.sh: echo hello return echo goodbye 运行script1.sh ,您会看到: hello hello again 回答2 更改环境变量是否重要? 因为否则您可以通过不带源代码执行脚本来执行脚本: someneatscriptthatendsprematurely.sh 回答3 我刚才有同样的问题 我意识到
  • 从 subprocess.Popen 调用“源”命令(Calling the "source" command from subprocess.Popen)
    问题 我有一个 .sh 脚本,我用source the_script.sh调用source the_script.sh 。 定期调用这个很好。 但是,我试图通过subprocess.Popen从我的 python 脚本调用它。 从 Popen 调用它,我在以下两个场景调用中收到以下错误: foo = subprocess.Popen("source the_script.sh") Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/lib/python2.7/subprocess.py", line 672, in __init__ errread, errwrite) File "/usr/lib/python2.7/subprocess.py", line 1213, in _execute_child raise child_exception OSError: [Errno 2] No such file or directory >>> foo = subprocess.Popen("source the_script.sh", shell = True) >>> /bin/sh: source: not found 是什么赋予了? 当我可以在 python
  • Linux系统脚本的三种执行方式
    1、source命令用法: source FileName 作用:在当前bash环境下读取并执行FileName中的命令。该filename文件可以无"执行权限" 注:该命令通常用命令“.”来替代。 如:source bash_profile . bash_profile两者等效。 source(或点)命令通常用于重新执行刚修改的初始化文档。 source命令(从 C Shell 而来)是bash shell的内置命令。 点命令,就是个点符号,(从Bourne Shell而来)。就是顺序的执行文件里的命令而已。2、sh和bash命令用法: sh FileName bash FileName 作用:在当前相应的bash环境下新建一个子shell读取并执行FileName中的命令。该filename文件可以无"执行权限" 注:两者在执行文件时的不同,是分别用自己的shell来跑文件。 sh使用“-n”选项进行shell脚本的语法检查,使用“-x”选项实现shell脚本逐条语句的跟踪,可以巧妙地利用shell的内置变量增强“-x”选项的输出信息等。3、./的命令用法: ./FileName 作用:打开一个子shell来读取并执行FileName中命令。 该文件必须有可执行的权限。 注:运行一个shell脚本时会启动另一个命令解释器. 每个shell脚本有效地运行在父shell
  • 在 bash 中用其内容替换“源文件”并扩展变量(Replacing 'source file' with its content, and expanding variables, in bash)
    问题 在 script.sh 中, source a.sh source b.sh CMD1 CMD2 CMD3 如何将source *.sh替换为其内容(不执行命令)? 我想看看 bash 解释器在获取文件并扩展所有变量后执行什么。 我知道我可以使用set -n -v或运行bash -n -v script.sh 2>output.sh ,但这不会替换源命令(如果 a.sh 或 b.sh 包含变量,则更少)。 我想过使用子shell,但这仍然没有扩展源代码行。 我在源代码行之前和之后尝试了set +n +v和set -n -v的组合,但这仍然不起作用。 我将使用 ssh 将该输出发送到远程机器。 我可以使用<<output.sh将内容通过管道传输到 ssh 命令中,但我无法以 root 身份登录到远程机器上,但我是一个 sudoer。 因此,我认为我可以创建脚本并将其作为 base64 编码的字符串发送(使用那个聪明的技巧) base64 script | ssh remotehost 'base64 -d | sudo bash' base64 script | ssh remotehost 'base64 -d | sudo bash' 有解决办法吗? 还是你有更好的主意? 回答1 你可以这样做: 内联.sh: #!/usr/bin/env bash while read
  • rvm安装不起作用:“ RVM不是功能”(rvm installation not working: “RVM is not a function”)
    问题 我刚刚安装了RVM,但无法使其正常运行。 我的.profile文件末尾有这样一行: [[ -s "$HOME/.rvm/scripts/rvm" ]] && . "$HOME/.rvm/scripts/rvm" 我试图运行source .profile并重新启动终端,但是仍然,当我运行rvm use 1.9.2我得到了: RVM is not a function, selecting rubies with 'rvm use ...' will not work. 我的系统是Ubuntu 11.10。 回答1 您没有使用登录外壳。 此处描述了启用登录标志的过程,还可以在此处找到有关登录shell的一些详细信息。 因此,您需要在Gnome终端的设置中选中“以登录身份运行”选项。 设置该标志后,需要打开新的终端。 有时需要将命令设置为/bin/bash --login 。 对于远程连接,了解运行交互式ssh会话与执行单个命令之间的区别非常重要。 在运行ssh server并与之交互地使用服务器时,默认情况下您使用的是登录shell,但一切都很好,但是对于ssh server "command"您没有使用登录shell,并且需要使用ssh server 'bash -lc "command"'来运行它ssh server 'bash -lc "command"' 。
  • 如何将当前工作目录设置为Bash中脚本的目录?(How can I set the current working directory to the directory of the script in Bash?)
    问题 我正在写一个Bash脚本。 我需要当前的工作目录始终是脚本所在的目录。 默认行为是脚本中的当前工作目录是运行它的外壳程序的目录,但是我不希望出现这种情况。 回答1 #!/bin/bash cd "$(dirname "$0")" 回答2 以下内容也适用: cd "${0%/*}" 该StackOverflow答案中对语法进行了详细说明。 回答3 尝试以下简单的一线: 对于所有UNIX / OSX / Linux dir=$(cd -P -- "$(dirname -- "$0")" && pwd -P) 重击 dir=$(cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P) 注意:命令中使用双破折号(-)表示命令选项的结尾,因此包含破折号或其他特殊字符的文件不会破坏命令。 注意:在bash,使用${BASH_SOURCE[0]}赞成$0 ,否则路径可以采购它时破裂( source / . )。 对于Linux,Mac和其他* BSD: cd "$(dirname "$(realpath "$0")")"; 注意:默认情况下, realpath应该安装在最受欢迎的Linux发行版中(例如Ubuntu),但是在某些情况下可能会丢失,因此必须安装它。 注意:如果你正在使用bash,使用${BASH_SOURCE[0]}赞成
  • 在带有'source'的Dockerfile中使用RUN指令不起作用(Using the RUN instruction in a Dockerfile with 'source' does not work)
    问题 我有一个Dockerfile,我正在将其安装在一起以安装香草python环境(我将在其中安装应用程序,但稍后再安装)。 FROM ubuntu:12.04 # required to build certain python libraries RUN apt-get install python-dev -y # install pip - canonical installation instructions from pip-installer.org # http://www.pip-installer.org/en/latest/installing.html ADD https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py /tmp/ez_setup.py ADD https://raw.github.com/pypa/pip/master/contrib/get-pip.py /tmp/get-pip.py RUN python /tmp/ez_setup.py RUN python /tmp/get-pip.py RUN pip install --upgrade pip # install and configure virtualenv RUN pip install
  • 如何在bash中获取csh脚本以设置环境(how to source a csh script in bash to set the environment [closed])
    问题 关闭。 此问题不符合堆栈溢出准则。 它当前不接受答案。 想要改善这个问题吗? 更新问题,使它成为Stack Overflow的主题。 7年前关闭。 改善这个问题 我们在Solaris上运行Oracle,默认情况下外壳为csh。 因此,登录脚本还在csh中设置了oracle_home和oracle_sid。 但是我不喜欢csh,并且想要使用bash来完成我的工作。 那么如何在bash中获取csh登录脚本的源代码呢? 例如,以下是.cshrc文件中的内容。 当使用bash时,我想使用这些变量。 一种方法是再次复制变量并使用bash命令,例如export ORACLE_SID = TEST。 但是,这样做将需要我们维护文件的两个副本。 当我们更改数据库名称或升级数据库时,我需要单独维护bash登录文件。 只是使用类似的东西真是太好了 bash中的源.cshr,但是它不起作用。 setenv ORACLE_SID TEST setenv ORACLE_HOME /oracle/TEST/home/products/10204 setenv EPC_DISABLED TRUE setenv MANPATH /usr/local/man:/usr/share/man setenv EDITOR vi setenv LD_LIBRARY_PATH $ORACLE_HOME/lib:/usr