Linux 使用`sh`和`source`有什么区别?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13786499/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the difference between using `sh` and `source`?
提问by 0x90
What is the difference between sh
and source
?
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.
And for man sh
:
而对于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).
采纳答案by F. Hauri
When you call source
(or its alias .
), you load and execute a bash script into the currentbash process. So you can
当您调用source
(或其别名.
)时,您将 bash 脚本加载并执行到当前的bash 进程中。这样你就可以
- read variables set in the sourced script,
- use functions defined within it.
- and even execute forks and/or subprocess if script do this.
- 读取源脚本中设置的变量,
- 使用其中定义的函数。
- 如果脚本执行此操作,甚至执行分叉和/或子进程。
When you call sh
, you initiate a fork(sub-process or child) that runs a new session of /bin/sh
, which is usually a symbolic link to bash
. In this case, environment variables set by the sub-script would be dropped when the sub-script finishes.
当您调用 时sh
,您会启动一个分支(子进程或子进程)来运行 的新会话/bin/sh
,该会话通常是到 的符号链接bash
。在这种情况下,当子脚本完成时,子脚本设置的环境变量将被删除。
Caution: sh
could be a symlink to anothershell.
注意:sh
可能是另一个shell的符号链接。
One little sample
一小样
For example, if you want to change current working directoryby a specific manner, you could not do
例如,如果您想通过特定方式更改当前工作目录,则无法执行
$ cat <<eof >myCd2Doc.sh
#!/bin/sh
cd /usr/share/doc
eof
$ chmod +x myCd2Doc.sh
This won't do what you expect:
这不会做你期望的:
$ cd /tmp
$ pwd
/tmp
$ ~/myCd2Doc.sh
$ pwd
/tmp
because current working diris part of environment and myCd2Doc.sh
would run in a subshell.
因为当前的工作目录是环境的一部分,并且myCd2Doc.sh
会在subshell 中运行。
But:
但:
$ cat >myCd2Doc.source <<eof
# Shell source file
myCd2Doc() {
cd /usr/share/doc
}
eof
$ . myCd2Doc.source
$ cd /tmp
$ pwd
/tmp
$ myCd2Doc
$ pwd
/usr/share/doc
I wrote a little sample of mycd
function (with bashcompletion based on bash Associative Array).
我写了一个小mycd
函数示例(使用基于bash 关联数组的bash完成)。
Execution level $SHLVL
执行级别 $SHLVL
$ cd /tmp
printf %b '/bin/bash\necho This is level SHLVL.\n' >qlvl.sh
$ bash qlvl.sh
This is level 2.
$ source qlvl.sh
This is level 1.
Little recursion
小递归
$ cat <<eoqlvl2 >qlvl2.sh
#!/bin/bash
export startLevel
echo This is level $SHLVL started:${startLevel:=$SHLVL}.
((SHLVL<5)) && ./qlvl2.sh
eoqlvl2
$ chmod +x qlvl2.sh
$ ./qlvl2.sh
This is level 2 started:2.
This is level 3 started:2.
This is level 4 started:2.
This is level 5 started:2.
$ source qlv2.sh
This is level 1 started:1.
This is level 2 started:1.
This is level 3 started:1.
This is level 4 started:1.
This is level 5 started:1.
A little futher
有点远
$ sed '$a ps --sid $SID fw' qlvl.sh >qlvl3.sh
$ chmod +x qlvl3.sh
$ export SID
$ read SID < <(ps ho sid $$)
$ echo $SID $$
8983 8983
( Current PID($$
== process Id) are same identifier than SID(session ID). It's not alway true.)
(当前PID($$
==进程 ID)与SID(会话 ID)是相同的标识符。它并不总是正确的。)
$ ./qlvl3.sh
This is level 2.
PID TTY STAT TIME COMMAND
8983 pts/10 Ss 0:00 /bin/bash
10266 pts/10 S+ 0:00 \_ /bin/bash ./qlvl3.sh
10267 pts/10 R+ 0:00 \_ ps --sid 8983 fw
$ . qlvl3.sh
This is level 1.
PID TTY STAT TIME COMMAND
8983 pts/10 Ss 0:00 /bin/bash
10428 pts/10 R+ 0:00 \_ ps --sid 8983 fw
Dot .
is an alias of source
. So the only difference between two command are slash
replaced by space
.
点.
是 的别名source
。所以两个命令之间的唯一区别被slash
替换为space
.
And a finaltest:
和最终测试:
$ printf %b '/bin/bash\necho Ending this.\nsleep 1;exit 0\n' >finalTest.sh
$ bash finalTest.sh
Ending this.
$ source finalTest.sh
Ending this.
... You may notice a differentbehaviour between the two syntaxes. ;-)
...您可能会注意到两种语法之间的不同行为。;-)
回答by Basile Starynkevitch
The main difference is that they are executed in a different process.
主要区别在于它们在不同的进程中执行。
So if you source
a file foo
which does a cd
, the sourcing shell (e.g. your interactive shell in the terminal) is affected (and its current directory will change)
因此,如果您source
的文件foo
执行 a cd
,则源外壳(例如终端中的交互式外壳)会受到影响(并且其当前目录将更改)
If you execute sh foo
the cd
does not affect the sourcing shell, only the freshly created sh
process running foo
如果执行sh foo
的cd
,不影响采购外壳,仅新创建的sh
进程在运行foo
Read the Advanced Bash Scripting Guide.
阅读高级 Bash 脚本指南。
That difference is not specific to Linux; every Posix implementation would have it.
这种差异并不是 Linux 特有的。每个 Posix 实现都会有它。
回答by Aria2end
When you execute a program with sh command:
当您使用 sh 命令执行程序时:
- your terminal will use sh or Bourne Shell to execute the program .
- a new process is created because Bash makes an exact copy of itself . this child process has the same environment as its parent, only the process ID number is different. (this process called forking )
- you need to need to have execution permission to execute it ( since it is forking )
- 您的终端将使用 sh 或 Bourne Shell 来执行程序。
- 一个新进程被创建,因为 Bash 制作了它自己的精确副本。该子进程与其父进程具有相同的环境,只是进程 ID 号不同。(这个过程称为分叉)
- 您需要具有执行权限才能执行它(因为它正在分叉)
and when you use source command :
当您使用 source 命令时:
- you execute the program with your default interpreter
- you execute the process in your current terminal ( technically your *nix command interpreted )
- Since the program will be executed in current terminal you dont need to give it execution permission
- 您使用默认解释器执行程序
- 您在当前终端中执行该过程(从技术上讲,您的 *nix 命令已解释)
- 由于程序将在当前终端中执行,因此您无需授予它执行权限
回答by Will Vousden
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.
正如其他人所提到的,当您运行 时sh test.sh
,test.sh
对您的 shell 环境所做的任何更改都不会在该过程结束后持续存在。
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
).
但是,还要注意,当您的环境中没有导出的任何元素(例如,变量、别名和 shell 函数)test.sh
作为子进程(即使用sh test.sh
)执行时,代码将无法使用。
For example:
例如:
$ cat > test.sh
echo $foo
$ foo=bar
$ sh test.sh
$ . test.sh
bar
Example 2:
示例 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$
回答by rg665n
source(or . ) - runs inside current shell and changes its attribute/environment.
source(或 . ) - 在当前 shell 中运行并更改其属性/环境。
shdo fork and runs in a subshell and hence can't change attributes/environment.
sh执行 fork 并在子 shell 中运行,因此无法更改属性/环境。
For example
例如
My shell script is -
我的 shell 脚本是 -
elite12!rg6655:~/sh_pr [33]$ cat changeDir.sh
#!/bin/bash
cd /home/elt/rg6655/sh_pr/justdir
pwd
echo $$
My Current Shell -
我目前的壳 -
elite12!rg6655:~/sh_pr [32]$ echo $$
3272
Process id of my current shell is 3272
我当前 shell 的进程 ID 是 3272
Running with the source-
与源一起运行-
elite12!rg6655:~/sh_pr [34]$ source changeDir.sh
/home/elt/rg6655/sh_pr/justdir
3272
elite12!rg6655:~/sh_pr/justdir
Observer two things - 1) The process id (3272) is same as my shell, which confirms source executes in the current shell. 2) cd command worked and directory got changed to justdir.
观察两件事 - 1) 进程 id (3272) 与我的 shell 相同,它确认源在当前 shell 中执行。2) cd 命令生效,目录更改为 justdir。
Running with sh-
与sh 一起运行-
elite12!rg6655:~/sh_pr [31]$ sh changeDir.sh
/home/elt/rg6655/sh_pr/justdir
13673
elite12!rg6655:~/sh_pr
In this case, process id (13673) is different and directory remains the same which means it is running in a different process or subshell.
在这种情况下,进程 id (13673) 不同,目录保持不变,这意味着它在不同的进程或子 shell 中运行。