source 명령을 사용하여 외부 스크립트 시작

source 명령을 사용하여 외부 스크립트 시작

저는 훌륭한 튜토리얼과 스크립트를 읽으면서 쉘 스크립팅을 배워왔습니다.

나는 이것을 읽고 있다Minecraft 초기화 스크립트, 첫 번째 줄이 나에게 깊은 인상을 남겼습니다.

if [ -L $0 ]
then
    source `readlink -e $0 | sed "s:[^/]*$:config:"`
else
    source `echo $0 | sed "s:[^/]*$:config:"`
fi

따라서 이 줄은 동일한 셸(모든 구성 값이 저장되는 곳)에서 "config"라는 스크립트를 시작합니다. 그런데 왜 파일을 직접 실행하는 대신("소스 구성" 등을 사용하여) 스크립트 작성자가 원본 스크립트의 이름(링크인지 여부에 관계없이)을 읽고 결과를 보내 sed해당 이름을 대체합니다. "구성"으로?

답변1

소스 코드 사용

이 명령은 source다른 스크립트를 실행하지 않습니다. 단지 다른 스크립트의 내용을 이 스크립트로 가져와 해당 내용이 원래 호출 스크립트의 일부인 것처럼 실행합니다.

이는 기본적으로 다른 스크립트의 내용을 자신의 것과 동일한 범위에 포함시키는 메커니즘입니다.

읽기 링크 사용

이 명령은 원본 스크립트가 링크를 통해 호출되는 경우 존재합니다.

sed 사용

이 스크립트는 sed를 사용하여 호출 스크립트의 이름을 name으로 변환합니다 config.

다음과 같은 스크립트가 있다고 가정해 보겠습니다 orig.bash.

#!/bin/bash

printf "exectued as:  %s\n" $0
cmd=$(readlink -e $0 | sed "s:[^/]*$:config:")
printf "sourcing as:  %s\n" "$cmd"

이 프로그램은 두 가지 작업을 수행합니다.

  1. 인쇄된 값$0

    printf "exectued as:  %s\n" $0
    
  2. readlink ...인쇄 명령 값

    cmd=$(readlink -e $0 | sed "s:[^/]*$:config:")
    printf "sourcing as:  %s\n" "$cmd"
    

이제 이 스크립트에 대한 링크를 만들어 보겠습니다 link2orig.bash. 이제 디렉토리에 다음 파일이 있습니다.

# creates link
$ ln -s orig.bash link2orig.bash

# results after
$ ls -l
total 4
lrwxrwxrwx 1 saml saml   9 Sep  5 06:23 link2orig.bash -> orig.bash
-rwxrwxr-x 1 saml saml 126 Sep  5 06:31 orig.bash

이제 무슨 일이 일어나는지 보자

이제 실제 이름이나 링크를 사용하여 예제 스크립트를 실행할 때 문자열을 호출자의 인수로 바꿀 수 있습니다 config. 이는 우리가 소싱하는 스크립트에 대한 구성 정보가 포함된 또 다른 파일입니다.

$ ./orig.bash 
executed as:  ./orig.bash
sourcing as:  /home/saml/tst/89518/config

$ ./link2orig.bash 
executed as:  ./link2orig.bash
sourcing as:  /home/saml/tst/89518/config

아시다시피, 이 접근 방식의 장점 중 하나는 시스템의 다양한 위치에서 다양한 방식으로 호출되는 것에 매우 관대하다는 것입니다.

$ ../89518/orig.bash 
executed as:  ../89518/orig.bash
sourcing as:  /home/saml/tst/89518/config

$ ../89518/link2orig.bash 
executed as:  ../89518/link2orig.bash
sourcing as:  /home/saml/tst/89518/config

답변2

$0스크립트의 경로입니다. 일반적으로 스크립트의 전체 경로입니다(즉, 로 시작하는 절대 경로 /). 스크립트가 실행 가능하고 shebang 줄로 시작하는 일반적인 경우 경로는 전체 경로가 됩니다. 그러나 셸이 명시적으로 호출되는 경우 $0이는 사용자가 명령줄에 입력하는 모든 항목이며 경로를 포함하지 않을 수 있습니다( cd somedir; bash minecraft, $0is 사용 minecraft). 표준 입력에서 스크립트를 사용하여 쉘을 호출하는 경우 $0쉘의 이름 또는 경로( bash <minecraft, $0is bash)입니다.

기호 링크를 통해 스크립트에 액세스하는 경우 스크립트는 링크의 전체 경로와 readlinkLinux 관련 유틸리티를 통해 확장된 기호 링크를 검색합니다.

이름 변환은 스크립트의 기본 이름을 config. 즉, yes인 경우 $0(또는 readlink $0경우에 따라) /path/to/minecraftsed 명령은 를 출력합니다 /path/to/config. 경로 에 다음이 포함되지 않은 경우에도 작동합니다 /.minecraftconfig

스크립트의 요점은 config스크립트와 동일한 디렉터리에서 호출된 파일을 찾아 해당 파일을 얻는 것입니다(즉, 호출 스크립트와 동일한 컨텍스트에서 스크립트를 읽고 실행하는 것). 나중에 스크립트에서 사용되는 변수를 config정의하는 구성 파일입니다 .minecraft

스크립트 누락변수 및 명령 대체는 큰따옴표로 묶입니다.. 다음과 같이 작성해야 합니다.

if [ -L "$0" ]
then
    source "$(readlink -e "$0" | sed 's:[^/]*$:config:')"
else
    source "$(echo "$0" | sed 's:[^/]*$:config:')"
fi

스크립트 경로에 -개행 문자가 포함되거나 포함되어 있으면 여전히 실패하지만 이런 경우는 드뭅니다.

셸 문자열 조작 구성을 사용하여 동일한 아이디어( 에 대한 외부 호출 제외 readlink)를 작성할 수 있습니다.

case $0 in */*) config=$0;; *) config=./$0;; esac  # make sure there is a / in $config
if [ -L "$config" ]; then config=$(readlink -e -- "$config"); fi
config=${config%/*}/config

관련 정보