69

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.

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

5 回答 5

97

当您调用sourceor时.(一个是另一个的别名。cmdsource不是 POSIX 类型的bashism),您将 bash 脚本加载并执行当前bash 进程中。这样你就可以

  • 读取源脚本中设置的变量,
  • 使用其中定义的函数。
  • 如果脚本执行此操作,甚至执行分叉和/或子进程。

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

注意sh可能是另一个shell 的符号链接。

实用样本

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

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

$ chmod +x myCd2Doc.sh

这不会像你期望的那样:

$ cd /tmp
$ pwd
/tmp
$ ~/myCd2Doc.sh
$ pwd
/tmp

因为当前工作目录是 environment 的一部分,并且myCd2Doc.sh会在subshel​​l中运行。

但:

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

$ . myCd2Doc.source
$ cd /tmp
$ pwd
/tmp
$ myCd2Doc
$ pwd
/usr/share/doc

看看mycd功能!!(使用基于Associative Array的完成)。

执行级别$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.

递归(当脚本从自身运行时)

$ cat <<eoqlvl2 >qlvl2.sh 
#!/bin/bash

export startLevel recursionLimit=5
echo This is level $SHLVL started:${startLevel:=$SHLVL}.
(( SHLVL < recursionLimit )) && ./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.

再远一点

$ 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

(当前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

.是 的别名source。因此,两个命令之间的唯一区别被slash替换为space.

最后的测试:

$ printf %b '\43\41/bin/bash\necho Ending this.\nsleep 1;exit 0\n' >finalTest.sh

$ bash finalTest.sh 
Ending this.

$ source finalTest.sh
Ending this.

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

于 2012-12-09T10:13:05.987 回答
14

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

因此,如果您source的文件foo执行 a cd,则采购外壳(例如终端中的交互式外壳)会受到影响(并且其当前目录将更改)

如果您执行sh foocd影响采购外壳,只有新创建的sh进程运行foo

阅读高级 Bash 脚本指南

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

于 2012-12-09T10:09:45.950 回答
5

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

test.sh但是,还要注意,当代码作为子进程(即使用 )执行时,未导出的环境中的任何元素(例如变量、别名和 shell 函数)都将不可用于代码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$ 
于 2015-03-14T17:20:35.677 回答
3

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

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

例如

我的 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 中运行。

于 2019-08-20T16:28:30.263 回答
1

使用 sh 命令执行程序时:

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

当你使用 source 命令时:

  • 您使用默认解释器执行程序
  • 您在当前终端中执行该过程(从技术上讲,您的 *nix 命令已解释)
  • 由于程序将在当前终端中执行,因此您不需要授予它执行权限
于 2013-02-27T05:27:53.603 回答