使用`sh`和`source`有什么区别?

0x9*_*x90 52 unix linux bash shell

sh和之间有什么区别source

source: source filename [arguments]
    Read and execute commands from FILENAME and return.  The pathnames
    in $PATH are used to find the directory containing FILENAME.  If any
    ARGUMENTS are supplied, they become the positional parameters when
    FILENAME is executed.
Run Code Online (Sandbox Code Playgroud)

并为man sh:

NAME
       bash - GNU Bourne-Again SHell

SYNOPSIS
       bash [options] [file]

COPYRIGHT
       Bash is Copyright (C) 1989-2004 by the Free Software Foundation, Inc.

DESCRIPTION
       Bash  is  an sh-compatible command language interpreter that executes commands read from the standard input or from a file.  Bash also incorporates
       useful features from the Korn and C shells (ksh and csh).

       Bash is intended to be a conformant implementation of the IEEE POSIX Shell and Tools specification (IEEE Working Group 1003.2).
Run Code Online (Sandbox Code Playgroud)

F. *_*uri 68

当您调用source(或其别名.)时,您脚本插入当前的 bash进程中.所以你可以读取脚本设置的变量.

当你调用时sh,你启动一个运行新会话的fork(子进程)/bin/sh,它通常是一个符号链接bash.在这种情况下,子脚本完成后,将删除子脚本设置的环境变量.

警告:sh可能是另一个 shell 的符号链接.

一个小样本

例如,如果要以特定方式更改当前工作目录,则无法执行此操作

cat <<eof >myCd2Doc.sh
#!/bin/sh
cd /usr/share/doc
eof

chmod +x myCd2Doc.sh
Run Code Online (Sandbox Code Playgroud)

这不符合您的期望:

cd /tmp
pwd
/tmp
~/myCd2Doc.sh
pwd
/tmp
Run Code Online (Sandbox Code Playgroud)

因为当前工作的dir是环境的一部分,并且myCd2Doc.sh将在子shell中运行.

但:

cat >myCd2Doc.source <<eof
# Shell source file
myCd2Doc() {
    cd /usr/share/doc
}
eof

. myCd2Doc.source
cd /tmp
pwd
/tmp
myCd2Doc
pwd
/usr/share/doc
Run Code Online (Sandbox Code Playgroud)

(我写了一小部分mycd函数.)

执行级别 $SHLVL

cd /tmp
printf %b '\43\41/bin/bash\necho This is level \44SHLVL.\n' >qlvl.sh

bash qlvl.sh 
This is level 2.

source qlvl.sh 
This is level 1.
Run Code Online (Sandbox Code Playgroud)

递归

cat <<eoqlvl >qlvl.sh 
#!/bin/bash

export startLevel
echo This is level $SHLVL starded:${startLevel:=$SHLVL}.
((SHLVL<5)) && ./qlvl.sh
eoqlvl
chmod +x qlvl.sh

./qlvl.sh 
This is level 2 starded:2.
This is level 3 starded:2.
This is level 4 starded:2.
This is level 5 starded:2.

source qlvl.sh 
This is level 1 starded:1.
This is level 2 starded:1.
This is level 3 starded:1.
This is level 4 starded:1.
This is level 5 starded:1.
Run Code Online (Sandbox Code Playgroud)

最终测试:

printf %b '\43\41/bin/bash\necho Ending this.\nexit 0\n' >finalTest.sh

bash finalTest.sh 
Ending this.

source finalTest.sh
Ending this.
Run Code Online (Sandbox Code Playgroud)

...您可能会注意到两种语法之间存在不同的行为.;-)

  • 还应注意,任何未导出的环境变量将不可用于在新 shell 下调用的脚本。 (2认同)

Bas*_*tch 11

主要区别在于它们在不同的过程中执行.

所以,如果你source一个文件,foo它做了cd,采购壳(终端例如你的交互shell)受到影响(以及它的当前目录下会发生变化)

如果执行sh foocd,不影响采购外壳,仅新创建的sh进程在运行foo

阅读Advanced Bash脚本编写指南.

这种差异并非特定于Linux; 每个Posix实现都会拥有它.

  • 不,**不要**阅读Advanced Bash(实际上它们意味着Bug)脚本指南 (2认同)
  • 一种替代方法是 http://mywiki.wooledge.org/BashGuide,在 http://wiki.bash-hackers.org/scripting/tutoriallist 上有更多链接 (2认同)

Wil*_*den 5

As others have mentioned, when you run sh test.sh, any changes that test.sh makes to your shell environment won't persist after the process has ended.

However, also note that any element of your environment that isn't exported (e.g., variables, aliases, and shell functions) won't be available to the code in test.sh when it is executed as a subprocess (i.e. with sh test.sh).

For example:

$ cat > test.sh
echo $foo
$ foo=bar
$ sh test.sh
$ . test.sh
bar
Run Code Online (Sandbox Code Playgroud)

Example 2:

lap@my-ThinkPad:~$ cat test.sh
#!/bin/sh
cd /etc
lap@my-ThinkPad:~$ sh test.sh 
lap@my-ThinkPad:~$ pwd
/home/savoury
lap@my-ThinkPad:~$ source test.sh 
lap@my-ThinkPad:/etc$ pwd
/etc
lap@my-ThinkPad:/etc$ 
Run Code Online (Sandbox Code Playgroud)