지원되지 않는 "shopt" 옵션이 .bashrc에서 오류를 일으키는 것을 방지하려면 어떻게 해야 합니까?

지원되지 않는 "shopt" 옵션이 .bashrc에서 오류를 일으키는 것을 방지하려면 어떻게 해야 합니까?

저는 서로 다른 HPC 노드, 가상 머신 또는 개인 워크스테이션에서 서로 다른 버전의 Bash를 실행할 수 있는 상대적으로 이질적인 환경에서 일하고 있습니다. 로그인 스크립트를 Git 저장소에 넣었기 때문에 .bashrc"이 호스트라면..."과 같은 유형의 혼란 없이 전반적으로 동일한 스크립트를 사용하고 싶었습니다 .

좋다Bash 4.1 이하의 기본 동작은 키를 누를 때의 동작 cd $SOMEPATH으로 확장되었습니다. Bash 4.2 이상에서는 이 동작을 다시 활성화해야 합니다.cd /the/actual/pathTabshopt -s direxpand저것없는2029년 2월 4일까지. 하지만 이는 단지 예일 뿐이며 관련성이 있을 수 있는 또 다른 shopt옵션 complete_fullquote입니다 .정확히그 효과)는 v4.2의 기본 동작을 변경할 수도 있습니다.

그러나 direxpand이전 버전의 Bash는 인식되지 않으며 shopt -s direxpand내 에서 이 작업을 시도 하면 .bashrc이전 버전의 Bash를 사용하여 노드에 로그인할 때마다 콘솔에 오류 메시지가 인쇄됩니다.

-bash: shopt: direxpand: invalid shell option name

내가 하고 싶은 것은 shop -s direxpand이전 버전의 Bash에 영향을 주지 않고 강력한 방식으로 Bash > 4.1에서 옵션을 활성화하는 조건을 래핑하는 것입니다(, 오류 출력을 )로 리디렉션하는 것이 아닙니다 /dev/null.

답변1

오류를 로 리디렉션하는 것을 이해할 수 없습니다 /dev/null. 코드를 강력하게 만들려면 set -e다음과 같은 일반적인 관용구를 사용하세요 … || true.

shopt -s direxpand 2>/dev/null || true

옵션이 없을 때 일부 대체 코드를 실행하려면 다음 반환 상태를 사용하세요 shopt.

if shopt -s direxpand 2>/dev/null; then
  … # the direxpand option exists
else
  … # the direxpand option does not exist
fi

그러나 리디렉션 오류가 정말 마음에 들지 않으면 완료 메커니즘을 사용하여 자체 검사를 수행할 수 있습니다. 이는 bash 2.03 이하이고 프로그래밍 가능한 완료 기능이 없는 오래된 시스템이 없다고 가정합니다.

shopt_exists () {
  compgen -A shopt -X \!"$1" "$1" >/dev/null
}
if shopt_exists direxpand; then
  shopt -s direxpand
fi

이 방법은 일부 환경(예: Cygwin)에서 속도가 느린 분기를 방지합니다. 단순하기 때문에 2>/dev/null성능 면에서는 이길 수 없다고 생각합니다.

답변2

direxpand출력에 존재하는지 확인 shopt하고 존재하는 경우 활성화하십시오.

shopt | grep -q '^direxpand\b' && shopt -s direxpand

답변3

특정인을 식별할 때shopt옵션Bash의 일부 주/부/패치 버전에서 사용할 수 있으며 $BASH_VERSION변수 또는 배열의 요소를 확인하여 $BASH_VERSINFO[]조건부로 활성화할 수 있습니다.

이것은 Bash 4.2.29 이상에 대한 테스트입니다.direxpand 처음 소개된4.2 시리즈의 경우:

if [[ $BASH_VERSION == 4.2.* && ${BASH_VERSINFO[2]} -ge 29 ]] ||
   [[ ${BASH_VERSINFO[0]} -eq 4 && ${BASH_VERSINFO[1]} -ge 3 ]] ||
   [[ ${BASH_VERSINFO[0]} -ge 5 ]]; then
    shopt -s direxpand
fi

편집하다:분명히 말하면 이것은 로그인 스크립트의 오류 메시지를 단순히 무시하기 위한 과도한 엔지니어링 솔루션이지만, 어쨌든 내 참조를 위해 기록하고 싶었습니다.

주변 중괄호에 주목하세요.${BASH_VERSINFO[index]}(로케일에 따른) 어휘 비교 대신 정수를 수행하는 -eqand 사용도 필요합니다 . -gt인용되지 않은 경우 연산자의 RHS는 언급된 대로 Bash / 조건 에서 "extglob" 패턴 ==으로 처리됩니다 .[[]]여기, 이는 정규식 IMO보다 더 아름다운 "시작" 비교를 제공합니다.

이것$BASH_VERSINFO대량으로다음 출력에 표시되는 모든 정보가 포함되어 있습니다 bash --version.

bash --version | head -1
# result:
# GNU bash, version 4.3.48(1)-release (x86_64-pc-linux-gnu)

declare -p BASH_VERSINFO
# result:
# declare -ar BASH_VERSINFO='([0]="4" [1]="3" [2]="48" [3]="1" [4]="release" [5]="x86_64-pc-linux-gnu")'

언제아니요shoptLuciano가 제안한 접근 방식이 좋다는 Bash 버전이 지원되거나 동작이 변경된 문서에서 분명합니다 .

# note the '-q' so that the matched pattern isn't actually printed
shopt | grep -q direxpand && shopt -s direxpand

...Gilles가 제안한 솔루션처럼 오류( )를 무시 하고 꼭 필요한지 shopt -s direxpand 2>/dev/null확인해보세요 .$?

인용하다:1,2,
관련 독서:정장과 쇼핑, 왜 둘일까요?

관련 정보