В чем разница между использованием "sh" и "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.

И для 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).

Ответы

Ответ 1

Когда вы вызываете source (или его псевдоним .), вы вставляете script в текущий bash процесс. Таким образом, вы можете читать переменные, заданные script.

Когда вы вызываете sh, вы инициируете fork (подпроцесс), который запускает новый сеанс /bin/sh, который обычно является символической ссылкой на bash. В этом случае переменные среды, заданные под script, будут отброшены, когда закончится под script.

Внимание: sh может быть символической ссылкой на другую оболочку.

Один маленький образец

Например, если вы хотите изменить текущий рабочий каталог определенным образом, вы не сможете выполнить

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 будет работать в подоболочке.

Но:

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

Уровень выполнения $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 <<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.

И последний тест:

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

bash finalTest.sh 
Ending this.

source finalTest.sh
Ending this.

... Вы можете заметить другое поведение между обоими синтаксисами.; -)

Ответ 2

Основное отличие состоит в том, что они выполняются в другом процессе.

Итак, если вы source файл foo, который выполняет cd, на него влияет исходная оболочка (например, ваша интерактивная оболочка в терминале) (и ее текущий каталог будет изменяться)

Если вы выполняете sh foo, cd не влияет на оболочку источника, только только что созданный sh процесс foo

Прочтите Расширенное руководство Bash Scripting Guide.

Это отличие не относится к Linux; каждая реализация Posix имела бы это.

Ответ 3

Как sh test.sh другие, при запуске sh test.sh любые изменения, которые test.sh делает для вашей оболочки, не будут сохраняться после завершения процесса.

Однако также обратите внимание, что любой элемент вашей среды, который не экспортируется (например, переменные, псевдонимы и функции оболочки), не будет доступен для кода в test.sh когда он выполняется как подпроцесс (т. test.sh С sh test.sh).

Например:

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

Пример 2:

[email protected]:~$ cat test.sh
#!/bin/sh
cd /etc
[email protected]:~$ sh test.sh 
[email protected]:~$ pwd
/home/savoury
[email protected]:~$ source test.sh 
[email protected]:/etc$ pwd
/etc
[email protected]:/etc$ 

Ответ 4

Когда вы выполняете программу с командой sh:

  • ваш терминал будет использовать sh или Bourne Shell для выполнения программы.
  • создается новый процесс, потому что Bash делает точную копию самого себя. этот дочерний процесс имеет ту же среду, что и его родитель, только идентификатор процесса отличается. (этот процесс называется forking)
  • вам нужно иметь разрешение на выполнение для его выполнения (так как оно разворачивается)

и когда вы используете команду источника:

  • вы выполняете программу с помощью интерпретатора по умолчанию
  • вы выполняете процесс в своем текущем терминале (технически ваша интерпретированная команда * nix)
  • Так как программа будет выполнена в текущем терминале, вам не нужно предоставлять ему разрешение на выполнение.

Ответ 5

source (или.) - запускается внутри текущей оболочки и меняет ее атрибут/окружение.

sh делает форк и работает в подоболочке и поэтому не может изменить атрибуты/окружение.

Например,

Мой сценарий оболочки -

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

Идентификатор процесса моей текущей оболочки - 3272

Работает с источником -

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

Наблюдатель две вещи - 1) Идентификатор процесса (3272) идентичен моей оболочке, что подтверждает выполнение исходного кода в текущей оболочке. 2) команда cd сработала, и каталог был изменен на justdir.

Бег с sh -

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

В этом случае идентификатор процесса (13673) отличается, а каталог остается тем же, что означает, что он выполняется в другом процессе или подоболочке.