지원되지 않는 ‘shopt’옵션으로 인해 .bashrc에서 오류가 발생하지 않도록하려면 어떻게해야합니까? 로그인 스크립트를 Git 리포지토리에 넣었

다른 HPC 노드, VM 또는 개인 워크 스테이션에서 다른 버전의 Bash를 실행할 수있는 비교적 이기종 환경에서 작업합니다. 로그인 스크립트를 Git 리포지토리에 넣었 기 때문에 .bashrc“이 호스트라면 …”형식의 혼잡함없이 보드 전체에서 동일한 (ish) 을 사용하고 싶습니다 .

나는 같은 배쉬 ≤ 확장 4.1의 기본 동작 cd $SOMEPATHcd /the/actual/path가압 할 때 Tab키를 누릅니다. 배쉬 4.2 이상, 당신이해야 shopt -s direxpand하는이 동작을 다시 설정하고, 사용할 수있게하지 않았다 4.2.29까지 . 그러나 이것은 하나의 예일뿐입니다. 또 다른 관련 shopt옵션은 complete_fullquote(내가 정확히 무엇인지 모르지만 ) v4.2의 기본 동작을 변경했을 수도 있습니다.

그러나 direxpand이전 버전의 Bash에서는 인식하지 못하며 shopt -s direxpandmy에서 시도 .bashrc하면 이전 Bash가있는 노드에 로그인 할 때마다 오류 메시지가 콘솔에 인쇄됩니다.

-bash: shopt: direxpand: invalid shell option name

내가하고 싶은 것은 shop -s direxpand이전 버전의 Bash를 손상시키지 않고 ( , 오류 출력을로 리디렉션하는 것이 아니라) Bash> 4.1에서 해당 옵션을 강력한 방법으로 사용하도록 조건부를 감싸는 것 /dev/null입니다.



답변

direxpand출력에 있는지 확인하고 다음 과 같은 경우 shopt활성화하십시오.

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


답변

에 오류를 리디렉션하는 데 무엇이 문제인지 알 수 없습니다 /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성능면에서 이길 수는 없다고 생각합니다.


답변

Bash의 특정 메이저 / 마이너 / 패치 릴리스에서 특정 shopt옵션 을 사용할 수 있음을 확실히 알고 있으면 조건부로 $BASH_VERSION변수 $BASH_VERSINFO[]를 활성화하기 위해 변수 또는 배열 요소를 검사 할 수 있습니다 .

다음 은 4.2 시리즈 direxpand 에 처음 도입 된 버전 인 Bash 4.2.29 이상에 대한 테스트입니다 .

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

편집 : 분명히, 이것은 단순히 로그인 스크립트에서 오는 오류 메시지를 무시하는 엄청나게 과장된 솔루션이지만, 내 자신의 교화를 위해 관계없이 문서화하고 싶었습니다.

주위에 괄호 주 , 하는 요구, 그리고 사용 및 (로케일에 따라 다름) 어휘의 비교보다는 정수 수행합니다. 인용되지 않은 경우, 운영자 의 RHS 는 여기 에 명시된 바와 같이 Bash / 조건부 내에서 “외부로”패턴으로 취급 되는데, 이는 정규식 IMO보다 더 미학적 “시작으로”비교합니다.${BASH_VERSINFO[index]}-eq-gt==[[]]

$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")'

이 때 아닌 설명서에서 명확 shopt되는 배쉬 버전 (들) 지원 또는 그들의 행동을 변화되었고, 루치아노에 의해 제안 된 방법은 괜찮 :

# 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 , 3
관련 읽기 : 세트 및 쇼핑-왜 2입니까?


답변