지원되지 않는 'shopt'옵션으로 인해 .bashrc에서 오류가 발생하지 않도록하려면 어떻게해야합니까?


9

다른 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입니다.


내 대답이 어떻게 도움이되지 않습니까?
Luciano Andress Martini

@LucianoAndressMartini 그것은했고, 그것은 내 자신과 함께 끝내는 해결책 .bashrc입니다. 나는 아직도 $BASH_VERSINFO내 자신의 교화를 위해 실행중인 쉘의 메이저 / 마이너 버전을 조사 하는 데 사용하는 방법에 대한 기록을 원했다 . :)
TheDudeAbides

내 대답에서 프로그램 버전과 셸 스크립트를 비교하는 것에 대해 뭔가가 있습니다.
Luciano Andress Martini

답변:


14

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

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

4
grep -q '^direxpand\b'bash의 향후 버전이나 포크에 이것을 하위 문자열로 포함 하고 제거 하는 옵션이있는 경우 더 direxpand좋습니다. 이 특정 경우와 달리 강력하지만 비용이 많이 들지 않습니다.
Gilles 'SO- 악마 그만해'

고마워요 Luciano. 본인의 질문에 답변을하려고했지만 편집 내용을 검토 한 후에 답변을 수락하겠습니다.
TheDudeAbides

4
Bash는 특정 쉘 옵션을 쿼리 할 수 ​​있으므로 사용할 수 있습니다 [ -z "$(shopt -po direxpand 2>&-)" ] || shopt -s direxpand. 더 이상 정규 표현식 문제가 없습니다! :-)
David Foerster

@DavidFoerster 나는 논리를 바꾸겠다 : [ -n "blah" ] && shopt blah당신이 그것을 표현하는 방식으로, "direxpand가 지원되지 않으면, 이것을하지 마십시오"라고 말하는 것입니다.
Rich

1
@ Rich : 대부분의 쉘 스크립트는 set -e맨 위에 포함 되어 있으므로이 방법 으로 바로 가기 논리를 사용하는 경향이 있습니다.
David Foerster

16

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


그것은 내 두뇌가 사라진 곳 이 아니라compgen 제안을 좋아합니다 . 그것은 바로 대표성 수준의 물건입니다! 리디렉션을 피하는 /dev/null것은 개인적인 취향입니다. 나는 용서 대신 허락을 구하고 싶습니다. :)
TheDudeAbides

Bash 프로그램 완성에서 전혀 예상치 못한 학교 교육을 위해 +1하여 설명서를 보러 가서 compgen -A shopt -X ...의미조차도 해독 했습니다.
TheDudeAbides

4
@TheDudeAbides 유닉스 및 리눅스compgen 에서이 방법을 사용 하는 것에 대해 읽은 사람은 누가 그것을 처음 제안했는지 모르겠습니다. (프로그래밍이 완료되기 전에 bash를 기본 셸로 사용하는 것을 중단했습니다.) 프로그래밍에서 권한 검사가 코딩으로 인해 실제로 수행중인 작업과 일치하지 않을 위험이 있으므로 일반적으로 권한을 요청하는 것은 좋지 않습니다. error (확인하려는 내용을 확인하지 않은 곳) 또는 사용하기 전에 확인한 내용이 변경 되었기 때문 입니다.
Gilles 'SO- 악마 그만

5

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입니까?


당신은 또한 같은 것을 사용할 수도 있습니다 if [[ $BASH_VERSION > 4.3 ]];(일치 4.3.0, 5.0등, 또한을 4.3.0-alpha나도 몰라 나중에 사실 문제의 경우..)
ilkkachu

@ilkkachu 님 안녕하세요. Bash v5.x를 포함하도록 편집 해 주셔서 감사합니다. 그러나 direxpand옵션은 실제로 Bash 4.2에서 사용할 수 있습니다. v4.2.53 의 Docker 이미지 로 실행 하여 이것을 확인했습니다 docker run --rm bash:4.2 bash -c shopt | grep direxpand(그리고 제대로 실행하려면 v4.1.17에서 실제로 사용할 수 없음docker run --rm bash:4.1 bash -c shopt | grep direxpand ).
TheDudeAbides

아 좋아, 나는 4.2.0그것이 작동하지 않는다는 사실을 테스트 하고 우연히 발견했다. 변경 로그는 또한 추가 언급 bash-4.3-alpha. 나는 하나 확인해야한다고 다음 가정 ${BASH_VERSINFO[2]}그것에 대해 정확하게는,하지만 난 그것을 추가하는 포인트 릴리스 모르는 ...
ilkkachu

우리는 기본적으로 Gilles가 위에서 만든 요점을 증명했다고 생각합니다. 그것은 사실, 더 좋은 단지 인 것이 시도 가 지원되지 않는 경우 쉘 옵션을 활성화하고 오류 처리 (또는 억제) 할 수 있습니다.
TheDudeAbides
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.