유일한 주요 차이점은 스크립트 소싱과 실행 간의 차이입니다. source foo.sh소스와 당신이 보여주는 다른 모든 예제가 실행 중입니다. 더 자세하게:
./file.sh
file.sh현재 디렉토리 ( ./) 에 있는 스크립트가 실행됩니다 . 일반적으로을 실행 command하면 셸은 디렉토리에서 $PATH라는 실행 파일을 찾습니다 command. 당신은 전체 경로를 제공하는 경우 등 /usr/bin/command이나 ./command, 그 다음은 $PATH무시되고 특정 파일이 실행됩니다.
../file.sh
이는 ./file.sh현재 디렉토리를 찾는 대신 file.sh상위 디렉토리 ( ../) 를 찾는 것을 제외하고 는 기본적으로 동일 합니다.
sh file.sh
이 동등한에는 sh ./file.sh, 위와 같이이 호출 한 스크립트 실행 file.sh현재 디렉토리에 있습니다. 차이점은 sh쉘을 사용하여 명시 적으로 실행한다는 것입니다 . 우분투 시스템에서는 dash그렇지 않습니다 bash. 일반적으로 스크립트에는 실행해야하는 프로그램을 제공 하는 shebang 줄 이 있습니다. 다른 것으로 호출하면 재정의됩니다. 예를 들면 다음과 같습니다.
$ cat foo.sh
#!/bin/bash
## The above is the shebang line, it points to bash
ps h -p $$ -o args='' | cut -f1 -d' ' ## This will print the name of the shell
이 스크립트는 단순히 실행에 사용 된 쉘의 이름을 인쇄합니다. 다른 방법으로 호출 할 때 반환되는 것을 보자.
$ bash foo.sh
bash
$ sh foo.sh
sh
$ zsh foo.sh
zsh
따라서 스크립트 호출을 호출 shell script하면 shebang 행 (있는 경우)을 무시하고 사용자가 지정한 쉘로 스크립트를 실행합니다.
source file.sh 또는 . file.sh
이것은 놀랍게도 스크립트를 소싱 하는 것입니다. 키워드 source는 쉘 내장 .명령 의 별명 입니다. 이것은 현재 쉘 내에서 스크립트를 실행하는 방법입니다. 일반적으로 스크립트가 실행될 때 현재 스크립트와 다른 자체 쉘에서 실행됩니다. 설명하기 위해 :
$ cat foo.sh
#!/bin/bash
foo="Script"
echo "Foo (script) is $foo"
이제 변수 foo를 부모 셸에서 다른 것으로 설정하고 스크립트를 실행하면 스크립트가 다른 값을 인쇄 foo하지만 (스크립트 내에 설정되어 있기 때문에) foo부모 셸 의 값은 변경되지 않습니다.
$ foo="Parent"
$ bash foo.sh
Foo (script) is Script ## This is the value from the script's shell
$ echo "$foo"
Parent ## The value in the parent shell is unchanged
그러나 스크립트를 실행하는 대신 소스를 지정하면 동일한 쉘에서 실행되므로 foo부모 의 값 이 변경됩니다.
$ source ./foo.sh
Foo (script) is Script ## The script's foo
$ echo "$foo"
Script ## Because the script was sourced,
## the value in the parent shell has changed
따라서 소싱은 스크립트가 실행중인 쉘에 영향을 줄 수있는 몇 가지 경우에 사용됩니다. 일반적으로 쉘 변수를 정의하고 스크립트가 완료된 후 사용 가능하게하는 데 사용됩니다.
모든 것을 염두에두고, 당신이 다른 대답을 얻는 이유는 무엇보다도 스크립트가 생각하는 것을하지 않기 때문입니다. bash의 출력에 나타나는 횟수를 계산합니다 ps. 이것은 열린 터미널의 수가 아니며 실행중인 쉘 의 수입니다 (사실, 그조차는 아니지만 다른 토론입니다). 명확히하기 위해 스크립트를 약간 단순화했습니다.
#!/bin/bash
logname=terdon
not=`ps -au$logname | grep -c bash`
echo "The number of shells opened by $logname is $not"
그리고 하나의 터미널 만 열어서 다양한 방법으로 실행하십시오 :
직접 발사 ./foo.sh.
$ ./foo.sh
The number of shells opened by terdon is 1
여기, 당신은 shebang 라인을 사용하고 있습니다. 이는 스크립트가 설정 한 내용에 따라 스크립트가 직접 실행됨을 의미합니다. 이는의 출력에 스크립트가 표시되는 방식에 영향을줍니다 ps. 대신에 상장되는 bash foo.sh, 그것은 단지로 표시됩니다 foo.sh당신의 그 어떤 수단 grep을 그리워합니다. 실제로는 3 개의 bash 인스턴스가 있습니다 : 부모 프로세스, 스크립트를 실행하는 bash 및 ps명령 을 실행하는 다른 bash 인스턴스 . 마지막으로 중요합니다. 명령 대체 ( `command`또는 $(command))를 사용하여 명령을 실행하면 부모 셸의 복사본이 시작되고 명령이 실행됩니다. 그러나 여기서는 ps출력 을 표시 하는 방식으로 인해 이들 중 어느 것도 표시되지 않습니다 .
명시 적 (bash) 셸을 사용하여 직접 시작
$ bash foo.sh
The number of shells opened by terdon is 3
여기에서를 실행하고 있기 때문에 bash foo.sh의 출력 ps이 표시 bash foo.sh되고 계산됩니다. 따라서 여기에는 부모 프로세스, bash스크립트 실행 및 복제 된 셸 (을 실행 ps)이 모두 표시되므로 ps명령에 단어가 포함되므로 각각에 표시됩니다 bash.
다른 쉘로 직접 시작 ( sh)
$ sh foo.sh
The number of shells opened by terdon is 1
당신이 스크립트를 실행하기 때문에이 다릅니다 sh하지 bash. 따라서 유일한 bash인스턴스는 스크립트를 시작한 상위 쉘입니다. 위에서 언급 한 다른 모든 쉘은 sh대신 실행 됩니다.
소싱 ( .또는 source같은 것)
$ . ./foo.sh
The number of shells opened by terdon is 2
위에서 설명한 것처럼 스크립트를 소싱하면 부모 프로세스와 동일한 셸에서 스크립트가 실행됩니다. 그러나 ps명령 을 시작하기 위해 별도의 서브 쉘이 시작되어 총 2 개가됩니다.
마지막으로 실행중인 프로세스를 계산하는 올바른 방법은 구문 분석이 ps아니라 사용하는 것 pgrep입니다. 당신이 방금 달리면 이러한 모든 문제를 피할 수 있었을 것입니다
pgrep -cu terdon bash
따라서 항상 올바른 숫자를 인쇄하는 작업 스크립트 버전은 다음과 같습니다 (명령 대체가 없음).
#!/usr/bin/env bash
user="terdon"
printf "Open shells:"
pgrep -cu "$user" bash
다른 모든 시작 방법에서는 소스가 공급되면 1이 반환되고 (스크립트를 실행하기 위해 새 bash가 시작되기 때문에) 2가 반환됩니다. sh자식 프로세스가 아니기 때문에 시작하면 여전히 1을 반환 bash합니다.