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

4 ответа

Решение

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

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

Осторожно: 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.

Маленькая рекурсия

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.

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

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

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

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

Прочитайте Расширенное руководство по написанию сценариев Bash.

Эта разница не характерна для Linux; каждая реализация Posix будет иметь это.

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

Однако также обратите внимание, что любой элемент вашей среды, который не экспортируется (например, переменные, псевдонимы и функции оболочки), не будет доступен для кода в 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$ 

source (or.) - runs inside current shell and changes its attribute/environment.

sh do fork and runs in a subshell and hence can't change attributes/environment.

For example

My shell script is -

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

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.

Running with 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.

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

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

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

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