다른 스크립트를 포함하는 가장 좋은 방법은 무엇입니까?
일반적으로 스크립트를 포함하는 방법은 "source"를 사용하는 것입니다.
예:
main.sh:
#!/bin/bash
source incl.sh
echo "The main script"
incl.sh:
echo "The included script"
「.main.sh」를 실행했을 때의 출력은 다음과 같습니다.
The included script
The main script
... 다른 위치에서 셸 스크립트를 실행하려고 하면 경로에 있지 않으면 포함을 찾을 수 없습니다.
스크립트가 포함 스크립트를 찾을 수 있도록 하는 좋은 방법은 무엇입니까?특히 스크립트를 이식할 필요가 있는 경우.
저는 모든 대본을 상대적인 것으로 만드는 경향이 있습니다.이렇게 하면 dirname을 사용할 수 있습니다.
#!/bin/sh
my_dir="$(dirname "$0")"
"$my_dir/other_script.sh"
파티에 늦은 건 알지만 스크립트를 어떻게 시작하고 빌트인을 독점적으로 사용하든 상관없습니다.
DIR="${BASH_SOURCE%/*}"
if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi
. "$DIR/incl.sh"
. "$DIR/main.sh"
.
는 (dot) 명령어에 에일리어스입니다.source
,$PWD
디렉토리의 입니다.BASH_SOURCE
가 소스 입니다.${string%substring}
는 $string의 에서 $합니다.
대체 수단:
scriptPath=$(dirname $0)
다음과 같습니다.
scriptPath=${0%/*}
..기본 명령어가 아닌 dirname에 의존하지 않는 것이 장점입니다(또한 에뮬레이터에서 항상 사용할 수 있는 것은 아닙니다).
는, 「동일 디렉토리」, 「동일 디렉토리」를 할 수 .dirname $0
:
#!/bin/bash
source $(dirname $0)/incl.sh
echo "The main script"
Chris Boran의 방법을 사용하는 것이 가장 좋은 방법이라고 생각합니다만, MY_DIR는 다음과 같이 계산해야 합니다.
#!/bin/sh
MY_DIR=$(dirname $(readlink -f $0))
$MY_DIR/other_script.sh
readlink의 man 페이지를 인용하려면:
readlink - display value of a symbolic link ... -f, --canonicalize canonicalize by following every symlink in every component of the given name recursively; all but the last component must exist
는 지금까지 지 i i i i i i i 。MY_DIR
가 올바르게 계산되지 않았습니다.의 심볼링크를 $PATH
그건 효과가 있다.
이 질문에 대한 답변을 조합하면 가장 강력한 솔루션을 얻을 수 있습니다.
의존관계 및 디렉토리 구조를 크게 지원하는 프로덕션급 스크립트로도 사용할 수 있었습니다.
#!/bin/module # 현재 스크립트의 풀패스THIS='readlink -f "${BASH_SOURCE[0]}" 2>/dev/disc||disclink $0" # 현재 스크립트가 있는 디렉토리DIR='dirname "${[THIS]" # '점'은 '소스'를 의미합니다. 즉, '포함': . "$DIR/compile.sh"
이 메서드는 다음 모두를 지원합니다.
- 경로 공간
- 링크(경유)
readlink
) ${BASH_SOURCE[0]}
튼튼하다$0
SRC=$(cd $(dirname "$0"); pwd)
source "${SRC}/incl.sh"
1. 가장 깔끔한
저는 거의 모든 제안을 검토했습니다.여기서 저에게 가장 잘 맞는 제안을 소개하겠습니다.
script_root=$(dirname $(readlink -f $0))
는 문자와 되어 있는 할 수 있습니다.$PATH
디렉토리로 이동합니다.
자세한 것은, https://github.com/pendashteh/hcagent/blob/master/bin/hcagent 를 참조해 주세요.
2. 가장 쿨한
# Copyright https://stackoverflow.com/a/13222994/257479
script_root=$(ls -l /proc/$$/fd | grep "255 ->" | sed -e 's/^.\+-> //')
이것은 실제로 이 페이지의 다른 답변에서 나온 것이지만, 저도 제 답변에 추가하고 있습니다!
3. 가장 신뢰할 수 있는 것
또는 드물게 이러한 방법이 작동하지 않는 경우에는 다음과 같은 방탄 방식을 사용할 수 있습니다.
# Copyright http://stackoverflow.com/a/7400673/257479
myreadlink() { [ ! -h "$1" ] && echo "$1" || (local link="$(expr "$(command ls -ld -- "$1")" : '.*-> \(.*\)$')"; cd $(dirname $1); myreadlink "$link" | sed "s|^\([^/].*\)\$|$(dirname $1)/\1|"); }
whereis() { echo $1 | sed "s|^\([^/].*/.*\)|$(pwd)/\1|;s|^\([^/]*\)$|$(which -- $1)|;s|^$|$1|"; }
whereis_realpath() { local SCRIPT_PATH=$(whereis $1); myreadlink ${SCRIPT_PATH} | sed "s|^\([^/].*\)\$|$(dirname ${SCRIPT_PATH})/\1|"; }
script_root=$(dirname $(whereis_realpath "$0"))
행해지고 에서 볼 수 .taskrunner
출처 : https://github.com/pendashteh/taskrunner/blob/master/bin/taskrunner
이것이 누군가에게 도움이 되기를 바랍니다:)
또한 해당 운영체제와 에뮬레이터가 작동하지 않을 경우 코멘트로 남겨주세요.감사합니다!
이것은, 스크립트가 다음의 소스인 경우에서도 동작합니다.
source "$( dirname "${BASH_SOURCE[0]}" )/incl.sh"
다른 스크립트의 위치를 지정해야 합니다.다른 방법은 없습니다.스크립트 상단에 설정 가능한 변수를 권장합니다.
#!/bin/bash
installpath=/where/your/scripts/are
. $installpath/incl.sh
echo "The main script"
또는 PROG_HOME이나 somesuch와 같이 사용자가 프로그램 홈의 위치를 나타내는 환경 변수를 유지하도록 할 수 있습니다.이 정보는 /etc/profile.d/에 해당 정보를 포함하는 스크립트를 작성함으로써 사용자에게 자동으로 제공할 수 있습니다.이 스크립트는 사용자가 로그인할 때마다 생성됩니다.
시스템 전체의 다양한 컴포넌트에 로케이션을 제공하는 것을 목적으로 하는 setenv 스크립트를 작성하는 것을 추천합니다.
setenv 스크립트를 사용하는 모든 스크립트에서 모든 위치가 공통되도록 다른 모든 스크립트에서 이 스크립트의 소스가 됩니다.
이는 cronjobs를 실행할 때 매우 유용합니다.cron을 실행하면 최소한의 환경을 얻을 수 있지만 먼저 모든 cron 스크립트에 setenv 스크립트를 포함하도록 설정하면 cronjobs를 실행할 환경을 제어하고 동기화할 수 있습니다.
우리는 약 2,000 kSLOC의 프로젝트에 걸쳐 지속적인 통합에 사용된 빌드 원숭이에 이러한 기술을 사용했습니다.
Shell Script Loader는 이를 위한 솔루션입니다.
include()라는 이름의 함수를 제공합니다.이 함수는 여러 스크립트에서 여러 번 호출하여 단일 스크립트를 참조할 수 있지만 스크립트는 한 번만 로드됩니다.함수는 완전한 경로 또는 부분 경로를 받아들일 수 있습니다(스크립트는 검색 경로에서 검색됨).load()라는 이름의 유사한 함수도 제공됩니다.이 함수는 스크립트를 무조건 로드합니다.
bash, ksh, pd ksh, zsh 각각에 최적화된 스크립트 및 ash, 대시, gareboom sh 등 일반적으로 원래의 sh와 호환되는 다른 셸에 대해 셸이 제공하는 기능에 따라 기능을 자동으로 최적화하는 유니버설스크립트를 통해 동작합니다.
[비겁한 예]
start.sh
이것은 옵션의 스타터 스크립트입니다.기동 방법을 여기에 배치하는 것은 편리할 뿐, 대신에 메인 스크립트에 배치할 수 있습니다.이 스크립트는 스크립트를 컴파일하는 경우에도 필요하지 않습니다.
#!/bin/sh
# load loader.sh
. loader.sh
# include directories to search path
loader_addpath /usr/lib/sh deps source
# load main script
load main.sh
main.sh
include a.sh
include b.sh
echo '---- main.sh ----'
# remove loader from shellspace since
# we no longer need it
loader_finish
# main procedures go from here
# ...
a.sh
include main.sh
include a.sh
include b.sh
echo '---- a.sh ----'
b.sh
include main.sh
include a.sh
include b.sh
echo '---- b.sh ----'
출력:
---- b.sh ----
---- a.sh ----
---- main.sh ----
가장 좋은 점은 이를 기반으로 한 스크립트를 컴파일하여 사용 가능한 컴파일러와 단일 스크립트를 형성할 수도 있다는 것입니다.
다음은 그것을 사용하는 프로젝트입니다.http://sourceforge.net/p/playshell/code/ci/master/tree/스크립트를 컴파일하거나 컴파일하지 않고 포터블하게 실행할 수 있습니다.단일 스크립트를 생성하기 위한 컴파일도 수행할 수 있으며 설치 시 유용합니다.
또, 구현 스크립트의 구조를 간단하게 알고 싶은 보수 정당을 위한 심플한 프로토타입도 작성했습니다.https://sourceforge.net/p/loader/code/ci/base/tree/loader-include-prototype.bash이것은 작고 누구나 자신의 코드가 Bash 4.0 이후와 함께 실행되도록 의도된 경우 메인 스크립트에 코드를 포함할 수 있으며, 또한 사용하지 않습니다.eval
.
Steve의 응답은 올바른 기술이지만 설치 경로 변수가 이러한 선언이 이루어지는 별도의 환경 스크립트에 포함되도록 리팩터링해야 합니다.
그러면 모든 스크립트가 해당 스크립트의 소스이며 installpath를 변경해야 합니다.한 곳에서만 변경하면 됩니다.미래를 대비할 수 있게 해 주죠세상에, 그 단어 정말 싫어!
BTW 예시와 같이 사용할 경우 ${installpath}를 사용하여 변수를 참조해야 합니다.
. ${installpath}/incl.sh
중괄호를 생략하면 일부 셸이 변수 "installpath/incl.sh"을 확장하려고 시도합니다.
모든 스타트업 스크립트를 .bashrc.d 디렉토리에 저장합니다.이것은 /etc/profile.d 등의 장소에서 일반적인 기술입니다.
while read file; do source "${file}"; done <<HERE
$(find ${HOME}/.bashrc.d -type f)
HERE
글로브를 이용한 해결책의 문제점은...
for file in ${HOME}/.bashrc.d/*.sh; do source ${file};done
파일 목록이 너무 길 수 있습니다.이런 접근법...
find ${HOME}/.bashrc.d -type f | while read file; do source ${file}; done
...환경은 원하는 대로 변화하지 않습니다.
이것은 신뢰성 있게 동작합니다.
source_relative() {
local dir="${BASH_SOURCE%/*}"
[[ -z "$dir" ]] && dir="$PWD"
source "$dir/$1"
}
source_relative incl.sh
source 또는 $0을 사용해도 스크립트의 실제 경로를 알 수 없습니다.스크립트의 프로세스 ID를 사용하여 실제 경로를 검색할 수 있습니다.
ls -l /proc/$$/fd |
grep "255 ->" |
sed -e 's/^.\+-> //'
이 스크립트를 사용하고 있기 때문에, 항상 도움이 됩니다.
물론 각자 다르겠지만, 아래 블록은 꽤 단단한 것 같아요.여기에는 디렉토리를 찾는 "최적의" 방법과 다른 bash 스크립트를 호출하는 "최적의" 방법이 포함됩니다.
scriptdir=`dirname "$BASH_SOURCE"`
source $scriptdir/incl.sh
echo "The main script"
따라서 이것이 다른 스크립트를 포함시키는 "최적의" 방법일 수 있습니다.이는 bash 스크립트의 저장 위치를 알려주는 다른 "최적의" 답변을 기반으로 합니다.
개인적으로는 모든 라이브러리를lib
폴더 및 사용import
로드하는 기능을 수행합니다.
폴더 구조
script.sh
내용물
# Imports '.sh' files from 'lib' directory
function import()
{
local file="./lib/$1.sh"
local error="\e[31mError: \e[0mCannot find \e[1m$1\e[0m library at: \e[2m$file\e[0m"
if [ -f "$file" ]; then
source "$file"
if [ -z $IMPORTED ]; then
echo -e $error
exit 1
fi
else
echo -e $error
exit 1
fi
}
이 Import 기능은 스크립트의 시작 부분에 있어야 하며 다음과 같이 라이브러리를 쉽게 Import할 수 있습니다.
import "utils"
import "requirements"
각 라이브러리의 맨 위에 한 줄씩 추가합니다(유틸리티).sh) :
IMPORTED="$BASH_SOURCE"
이제 내부 기능에 액세스할 수 있습니다.utils.sh
그리고.requirements.sh
부터script.sh
TODO: 링커를 작성하여 싱글을 구축합니다.sh
파일
incl.sh과 메인 폴더가 어디에 있는지 찾으면 됩니다.sh가 저장됩니다.메인만 변경해주세요sh:
main.sh
#!/bin/bash
SCRIPT_NAME=$(basename $0)
SCRIPT_DIR="$(echo $0| sed "s/$SCRIPT_NAME//g")"
source $SCRIPT_DIR/incl.sh
echo "The main script"
스크립트에 적합한 장소는 다음과 같습니다./usr/local/lib/
/usr/local/lib
로컬에 설치된 프로그램과 관련된 파일입니다.
저는 개인적으로/usr/local/lib/bash/includes
를 포함합니다.이와 같이 libs를 포함하기 위한 bash-helper lib가 있습니다.
#!/bin/bash
. /usr/local/lib/bash/includes/bash-helpers.sh
include api-client || exit 1 # include shared functions
include mysql-status/query-builder || exit 1 # include script functions
# include script functions with status message
include mysql-status/process-checker; status 'process-checker' $? || exit 1
include mysql-status/nonexists; status 'nonexists' $? || exit 1
내가 여기서 본 대부분의 답변들은 너무 복잡해 보인다.이 방법은 항상 안정적으로 작동했습니다.
FULLPATH=$(readlink -f $0)
INCPATH=${FULLPATH%/*}
INCPATH는 스크립트의 호출 방법($PATH, relative 또는 absolute)에 관계없이 스크립트 파일 이름을 제외한 스크립트의 전체 경로를 유지합니다.
그 후, 같은 디렉토리에 파일을 포함시키기 위해서만, 다음의 조작을 실시할 필요가 있습니다.
. $INCPATH/file_to_include.sh
레퍼런스:TecPorto / Location에 의존하지 않는 것
여기 당신이 사용할 수 있는 좋은 기능이 있습니다.@sacii가 만든 것을 기반으로 합니다.감사해요.
소스(스크립트 호출에 포함)에 공백으로 구분된 임의의 수의 스크립트 이름을 나열할 수 있습니다.source_files
).
옵션으로 첫 번째 인수로 절대 경로 또는 상대 경로를 전달할 수 있습니다.이 경로는 대신 여기에서 생성됩니다.
여러 번 호출할 수 있으며(아래 예 참조), 다른 dir에서 스크립트를 송신할 수 있습니다.
#!/usr/bin/env bash
function source_files() {
local scripts_dir
scripts_dir="$1"
if [ -d "$scripts_dir" ]; then
shift
else
scripts_dir="${BASH_SOURCE%/*}"
if [[ ! -d "$scripts_dir" ]]; then scripts_dir="$PWD"; fi
fi
for script_name in "$@"; do
# shellcheck disable=SC1091 disable=SC1090
. "$scripts_dir/$script_name.sh"
done
}
예를 들어, 이 예제를 실행하면 이 예제의 사용 방법을 알 수 있습니다.
#!/usr/bin/env bash
function source_files() {
local scripts_dir
scripts_dir="$1"
if [ -d "$scripts_dir" ]; then
shift
else
scripts_dir="${BASH_SOURCE%/*}"
if [[ ! -d "$scripts_dir" ]]; then scripts_dir="$PWD"; fi
fi
for script_name in "$@"; do
# shellcheck disable=SC1091 disable=SC1090
. "$scripts_dir/$script_name.sh"
done
}
## -- EXAMPLE -- ##
# assumes dir structure:
# /
# source_files.sh
# sibling.sh
# scripts/
# child.sh
# nested/
# scripts/
# grandchild.sh
cd /tmp || exit 1
# sibling.sh
tee sibling.sh <<- EOF > /dev/null
#!/usr/bin/env bash
export SIBLING_VAR='sibling var value'
EOF
# scripts/child.sh
mkdir -p scripts
tee scripts/child.sh <<- EOF > /dev/null
#!/usr/bin/env bash
export CHILD_VAR='child var value'
EOF
# nested/scripts/grandchild.sh
mkdir -p nested/scripts
tee nested/scripts/grandchild.sh <<- EOF > /dev/null
#!/usr/bin/env bash
export GRANDCHILD_VAR='grandchild var value'
EOF
source_files 'sibling'
source_files 'scripts' 'child'
source_files 'nested/scripts' 'grandchild'
echo "$SIBLING_VAR"
echo "$CHILD_VAR"
echo "$GRANDCHILD_VAR"
rm sibling.sh
rm -rf scripts nested
cd - || exit 1
인쇄:
sibling var value
child var value
grandchild var value
다음 항목도 사용할 수 있습니다.
PWD=$(pwd)
source "$PWD/inc.sh"
언급URL : https://stackoverflow.com/questions/192292/how-best-to-include-other-scripts
'UFO ET IT' 카테고리의 다른 글
Windows에서 Git Bash를 시작할 때 SSH 에이전트 실행 (0) | 2023.04.08 |
---|---|
R 스크립트 스케줄링 (0) | 2023.04.08 |
변수가 Bash의 숫자인지 테스트하려면 어떻게 해야 합니까? (0) | 2023.04.08 |
여러 파일의 확장자 이름을 변경하려면 어떻게 해야 합니까? (0) | 2023.04.08 |
WHERE 절의 참조 별칭(SELECT로 계산됨) (0) | 2023.04.08 |