unix 使用'sh'和'source'的区别是什么?

lrpiutwd  于 2022-11-04  发布在  Unix
关注(0)|答案(5)|浏览(193)

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).
zaq34kh6

zaq34kh61#

当您调用source.(一个是另一个的别名。source cmd不是POSIX. -类似于 bashism)时,您将在 * 当前 * shell进程中加载并执行一个shell脚本

  • 读取源脚本中设置的变量,
  • 使用其中定义的函数。
  • 甚至执行fork和/或子进程(如果脚本这样做话)。

当您调用sh时,您启动了一个 fork(子进程或 child),该进程运行/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

因为 * 当前工作目录 * 是环境的一部分,并且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

请看一下mycd function!!(带有基于 * 关联数组 * 的bash完成)。

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

Recursion(当脚本从自身运行时)

$ 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.\nsle' \
    'ep 1;exit 0\n' >finalTest.sh

$ bash finalTest.sh 
Ending this.

$ source finalTest.sh
Ending this.

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

sq1bmfud

sq1bmfud2#

主要区别在于它们在不同的进程中执行。
因此,如果您对执行cd的文件foo执行source操作,sourcing shell(例如,终端中的交互式shell)将受到影响(并且其当前目录将更改)
如果您执行sh foo,则cd不会影响sourcing shell,只会影响运行foo的新创建的sh进程
读取Advanced Bash Scripting Guide
这种差异并不是Linux特有的;每一个Posix系统都有它。

eagi6jfj

eagi6jfj3#

正如其他人所提到的,当运行sh test.sh时,test.sh对shell环境所做的任何更改在进程结束后都不会保留。
但是,还要注意,当test.sh作为子进程执行时(例如,使用sh test.sh),test.sh中的代码将无法使用环境中未导出的任何元素(例如,变量、别名和shell函数)。
例如:

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

例二:

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$

相关问题