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

时间:2012-12-09 10:07:13

标签: linux bash shell unix

shsource之间的区别是什么?

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.

对于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).

5 个答案:

答案 0 :(得分:64)

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

当您致电sh时,您启动 fork (子流程),该会话运行/bin/sh的新会话,该会话通常是{{1}的符号链接}}。在这种情况下,当子脚本完成时,子脚本设置的环境变量将被删除。

警告bash可能是另一个 shell的符号链接。

一个小样本

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

sh

这不符合您的期望:

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

chmod +x myCd2Doc.sh

因为当前工作目录是环境的一部分,cd /tmp pwd /tmp ~/myCd2Doc.sh pwd /tmp 将在子shell 中运行。

可是:

myCd2Doc.sh

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

执行级别cat >myCd2Doc.source <<eof # Shell source file myCd2Doc() { cd /usr/share/doc } eof . myCd2Doc.source cd /tmp pwd /tmp myCd2Doc pwd /usr/share/doc

$SHLVL

Little recursion

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.

最终测试:

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.

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

答案 1 :(得分:10)

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

因此,如果source文件foo执行cd,则源shell(例如终端中的交互式shell)会受到影响(并且其当前目录将会更改)< / p>

如果执行sh foocd不会影响采购外壳,则只有新创建的sh进程正在运行foo

阅读Advanced Bash Scripting Guide

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

答案 2 :(得分:3)

正如其他人所提到的,当您运行sh test.sh时,test.sh对您的shell环境所做的任何更改都不会在该过程结束后继续存在。

但是,请注意,环境中未导出的任何元素(例如,变量,别名和shell函数)都不会在test.sh中的代码中可用。作为子进程执行(即使用sh test.sh)。

例如:

$ cat > test.sh
echo $foo
$ foo=bar
$ sh test.sh
$ . test.sh
bar

示例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$ 

答案 3 :(得分:1)

使用sh命令执行程序时:

  • 您的终端将使用sh或Bourne Shell执行该程序。
  • 创建了一个新进程,因为Bash自己制作了一个精确的副本。此子进程与其父进程具有相同的环境,只有进程ID号不同。 (这个过程称为分叉)
  • 您需要具有执行权限才能执行它(因为它正在分叉)

当您使用source命令时:

  • 使用默认解释程序执行程序
  • 您在当前终端中执行该过程(从技术上讲,您的* nix命令已解释)
  • 由于程序将在当前终端中执行,因此您无需给予执行权限

答案 4 :(得分:1)

(或。)-在当前外壳中运行并更改其属性/环境。

sh 进行分叉并在子shell中运行,因此无法更改属性/环境。

例如

我的shell脚本是-

elite12!rg6655:~/sh_pr [33]$ cat changeDir.sh
#!/bin/bash
cd /home/elt/rg6655/sh_pr/justdir
pwd
echo $$

我当前的外壳-

elite12!rg6655:~/sh_pr [32]$ echo $$
3272

我当前shell的进程ID是3272

-

一起运行
elite12!rg6655:~/sh_pr [34]$ source changeDir.sh
/home/elt/rg6655/sh_pr/justdir
3272
elite12!rg6655:~/sh_pr/justdir

观察者两件事- 1)进程ID(3272)与我的Shell相同,它确认源代码在当前Shell中执行。 2)cd命令起作用,目录更改为justdir。

运行 sh -

elite12!rg6655:~/sh_pr [31]$ sh changeDir.sh
/home/elt/rg6655/sh_pr/justdir
13673
elite12!rg6655:~/sh_pr

在这种情况下,进程ID(13673)是不同的,并且目录保持不变,这意味着它在不同的进程或子Shell中运行。