Bash 소스 - 두 소스 파일이 동일한 함수 이름을 가질 때 올바른 함수를 선택합니까?

Bash 소스 - 두 소스 파일이 동일한 함수 이름을 가질 때 올바른 함수를 선택합니까?

file2.sh내 bash 스크립트는 매개변수를 기반으로 스크립트 파일(호출)을 가져옵니다. (소스가 있거나 없거나 둘 중 하나입니다.) 스크립트 file2.sh에는 "foo" 함수(foo의 수정되거나 개선된 버전이라고 함)가 포함되어 있습니다.

스크립트는 file1.sh원래 함수 "foo"를 포함하는 다른 파일( )도 가져옵니다. 이( file1.sh)는 항상 소스입니다(그리고 필요한 다른 기능도 있습니다).

file2.shfile1.sh(소스인 경우)의 "foo"를 재정의 하려면 "foo" 함수가 필요합니다 file2.sh.

또한 기본 스크립트에서 호출하는 모든 스크립트에서 이 작업을 수행해야 합니다. 스크립트 파일이라고 불리는 몇몇 소스 코드도 마찬가지입니다 file1.sh. 그들은 원래의 "foo" 기능을 기대합니다. 하지만 수정하지 않고 개선된 "foo"를 호출하도록 해야 합니다.

즉, 메인 스크립트에 "foo"가 포함되어 있으면 대신 "foo"를 사용하는 file2.sh소스 스크립트(메인 스크립트에 의해 호출됨)를 원합니다 . 기본 스크립트를 제외한 다른 파일은 변경할 수 없습니다. (또는 변경하는 경우 기본 스크립트에서 소스가 제공되지 않을 때 올바르게 작동하려면 필요합니다.)file1.shfile2.shfile2.sh

답변1

file2.sh에서 기능을 "읽기 전용"으로 표시할 수 있습니다.

참고: 이로 인해 file1.sh가 나중에 함수를 정의(재정의)하려고 시도할 때 경고가 발생합니다.

이러한 경고는 stderr에 표시되며 문제를 일으킬 수 있습니다. 비활성화할 수 있는지는 모르겠습니다.

추가 참고 사항: 스크립트가 함수 정의의 반환 상태를 확인하는 경우 이로 인해 스크립트가 실패할 수 있습니다. 스크립트 실행을 중단하기 위해 어디서나 0이 아닌 반환 상태를 발생시키는 bash 옵션을 설정하는 것도 가능하다고 생각합니다. 행운을 빌어요!

file1.sh를 수정할 수 있나요? 함수를 정의하기 전에 조건을 사용하여 함수가 정의되었는지 확인하는 것이 더 안정적인 솔루션이 될 것입니다.

이것은 "읽기 전용" 사용의 예입니다.

hobbes@metalbaby:~/scratch$ mkdir bash-source-test
hobbes@metalbaby:~/scratch$ cd bash-source-test
hobbes@metalbaby:~/scratch/bash-source-test$ cat > file2.sh
#!/bin/bash
fname(){
  echo "file2"
}

readonly -f fname
hobbes@metalbaby:~/scratch/bash-source-test$ cat > file1.sh
#!/bin/bash
fname(){
  echo "file1"
}

readonly -f fname
hobbes@metalbaby:~/scratch/bash-source-test$ cat >top.sh
#!/bin/bash 
if [ $1 ]; then
source file2.sh
fi  
source file1.sh

fname
hobbes@metalbaby:~/scratch/bash-source-test$ chmod +x *.sh
hobbes@metalbaby:~/scratch/bash-source-test$ ./top.sh 
file1
hobbes@metalbaby:~/scratch/bash-source-test$ ./top.sh hello
file1.sh: line 4: fname: readonly function
file2
hobbes@metalbaby:~/scratch/bash-source-test$ 

답변2

이러한 스크립트가 실제로 해석되고 ( 시뮬레이션 모드 bash가 아닌 경우 ) 정의되었지만 그렇지 않은 경우shfile1.sh사용 foosource, 예를 들어 다른 항목에 별칭을 지정하여 소스가 재정의되지 않도록 재정의하고 명령할 수 있습니다 ..file1.shfile1.shfoo

$ cat file1.sh
foo() { echo original foo; }
$ cat file2.sh
foo() { echo new foo; }
$ cat main.sh
file2_sourced=false
source() {
  case ${1##*/} in
    (file2.sh)
      file2_sourced=true;;
    (file1.sh)
      if "$file2_sourced"; then
        alias foo=original_foo

        builtin source "$@"; local "ret=$?"
        unalias foo
        return "$ret"
      fi;;
  esac
  builtin source "$@"
}
.() { source "$@"; }

source file2.sh
source file1.sh

foo
original_foo

$ bash main.sh
new foo
original foo

아니면 더 적절할 수도 있습니다:

source() {
  shopt -s expand_aliases
  if [ "${1##*/}" = file1.sh ] && command -v foo > /dev/null 2>&1; then
    # foo already defined, make file1.sh define original_foo this time
    alias foo=original_foo
    builtin source "$@"; local "ret=$?"
    unalias foo
    return "$ret"
  else
    builtin source "$@"
  fi
}

즉, file1.sh예방 만 하세요.~에 대한-정의 foo.

이제 호출된 다른 스크립트가 main.sh다음과 같다 면처형된되는 대신에원천source, 이러한 기능 과 .기능을 다음으로 내보내야 합니다 main.sh.

export -f source .

사실, 그것은 할 수 있습니다아니요수정하고 main.sh호출하세요.

env BASHOPTS=expand_aliases source='() {
  if [ "${1##*/}" = file1.sh ] && command -v foo > /dev/null 2>&1; then
    # foo already defined, make file1.sh define original_foo this time
    alias foo=original_foo
    builtin source "$@"; local "ret=$?"
    unalias foo
    return "$ret"
  else
    builtin source "$@"
  fi
}' .='() { source "$@"; }' bash main.sh

답변3

나는 기본 시스템 관리 및 자동화 작업을 위한 작은 bash 스크립트 외에는 아무것도 작성한 적이 없기 때문에 다른 파일에서 기능을 가져오는 경험이 거의 없습니다. 따라서 이것은 매우 순진하거나 이식 불가능할 수 있지만 적어도 내 시스템과 내가 아는 대부분의 프로그래밍 언어에서는 무언가를 재정의하면 재정의된 상태로 유지됩니다.

즉, 출처를 확인하는 한file1.sh 앞으로 file2.shfile2.sh그런 다음 로드된 경우 항상 내보내고, file1.sh로드되지 않은 경우 항상 내보내야 하는 함수를 내보냅니다.

$ cat file1.sh 
#!/bin/bash
fname(){
  echo "BBBBB"
}

$ cat file2.sh 
#!/bin/bash
fname(){
  echo "CCCCC"
}

$ cat foobar.sh 
#!/bin/bash
source file1.sh
if [ $1 ]; then 
    source file2.sh;
fi
export -f fname;
./run_function.sh

$ cat run_function.sh 
#!/bin/bash
fname

(예: )이라는 스크립트에는 콘텐츠가 정의 ./run_function.sh되어 있습니다 .fname마지막file2.sh, 리소스를 가져왔거나 file.sh아직 가져오지 않은 경우 리소스를 로드합니다 .

$ ./foobar.sh
BBBBB
$ ./foobar.sh hello
CCCCC

답변4

여기서 가장 간단한 대답은 이러한 스크립트 파일에서 함수를 가져오는 것일 수 있다고 생각합니다.

#file[12]
#foo() { : removed; }
. ./foo.fn
#and rest of script

#foo.fn
foo() { : old version is always defined; }
[ -z "${NEWFOO:+1}" ] ||
foo() { : new version defined only if $NEWFOO; }

#your caller script
export NEWFOO=1
case $srcarg in (./file1) unset NEWFOO;; esac
#or however ^that part^ is usually done
. "$srcarg"
#and rest of script

관련 정보