В чем разница между использованием `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 интерпретируется)
- Поскольку программа будет выполняться в текущем терминале, вам не нужно давать ей разрешение на выполнение.