ksh 버전을 안전하게 얻으려면 어떻게해야합니까?


12

ksh 스크립트 내에서 ksh 버전을 안전하게 얻으려면 어떻게 해야합니까?

다음과 같은 해결책 을 보았습니다 .

  1. ksh --version
  2. echo ${.sh.version}
  3. echo $KSH_VERSION

올바른 환경에서 이러한 각 작업이 올바르게 작동합니다. 그러나 나는 완벽하지 않은 경우에 관심이 있습니다.

특히, 이전 버전의 ksh를 사용하는 여러 시스템이 있는데, 그 목적 상 기능이 심각하게 부족합니다. 어쨌든, (프로그래밍 방식으로) 버전을 확인하려는 이유는 ksh 버전이 성능이 떨어지는 버전 중 하나인지 확인하는 것입니다. 그렇다면 덜 멋진 코드로 분기를 실행하고 싶습니다.

그러나 문제가있는 컴퓨터에서 쉘의 부적격은 버전 확인으로 확장됩니다 ...

  • 시도 ksh --version하면 아무것도 인쇄되지 않고 새로운 인스턴스가 열립니다 ksh!
  • 시도 echo ${.sh.version}하면 ksh이것을 버릴 수없는 구문 오류로 취급합니다 2> /dev/null.

    $ echo ${.sh.version} 2> /dev/null  
    ksh: ${.sh.version}: bad substitution
    
  • 물론 echo $KSH_VERSION제대로 작동하는 것 같습니다 – 충돌하지 않을 것입니다 –이 머신에서는 비어 있습니다. 또한에 의해 설정된 곳 을 보았습니다 .KSH_VERSIONpdksh

질문 :

  • ksh프로그래밍 방식으로 버전을 안전하게 확인할 수있는 방법은 무엇입니까? 여기서는 실제 버전 번호가 낡은 버전인지 여부를 실제로 신경 쓰지 않습니다 ksh.
  • 가 $KSH_VERSION충분한은? 비어 있다면 ksh반드시 구식 버전입니까? 다른 포럼에서 최신 버전의 경우에도 설정되지 않을 수 있다고 수정 ksh했습니까?
  • 이것을 전혀 확인할 방법이 없습니까?

1
덜 멋진 코드가있는 단일 경로가 아닌 두 개의 코드 경로를 원하는 이유는 무엇입니까?
— Thorbjørn Ravn Andersen

@ ThorbjørnRavnAndersen 그것은 프롬프트와 관련이 있습니다. .kshrc 파일에는 tcsh 및 zsh 프롬프트의 pwd 축약 기능을 시뮬레이트하는 기능이 있으며이 기능 PS1을 사용하도록 설정했습니다 . 그러나 Old ksh는 $()에서 지원하지 않습니다 PS1. 최신 버전의 ksh라면 PS1내가 만든 함수를 사용하고 싶습니다 . 이전 버전이라면 그냥 사용 $PWD합니다.
— Sildoreth

글쎄, 당신은 수 (아마도 하나가 다른에서 생성)을 구성 파일의 두 가지 버전이 다음 문제의 컴퓨터에 해당하는 버전을 배포?
— Thorbjørn Ravn Andersen

또 다른 접근 방법은 단순히 "문제가있는 특정 머신 일뿐입니다. 파일이나 환경 변수 또는 여기에만 존재하는 것 (아마도 AIX 또는 무언가)을 찾아서 대신 테스트 해 보겠다"고 말할 수 있습니다.
— Thorbjørn Ravn Andersen

답변:


7

나는 그것이 .sh.versionATT ksh 93의 첫 번째 버전 이후로 존재 했다고 생각합니다 . pdksh 또는 mksh에서는 사용할 수 없습니다. 때문에 ${.sh.version}경우 ksh93 이외의 껍질에 구문 오류가, 서브 쉘에 대한 테스트를 포장하고 뒤에 그것을 보호 eval.

_sh_version=$(eval 'echo "${.sh.version}"' 2>/dev/null) 2>/dev/null
case $_sh_version in
  '') echo "This isn't ATT ksh93";;
  …
esac

KSH_VERSION 공개 도메인 ksh 클론 (pdksh)에서 시작하여 2008 년 ksh93t를 사용하여 비교적 최근에 실제 Korn 쉘에 추가되었습니다.

버전 번호를 테스트하는 대신 슬픔을주는 특정 기능을 테스트해야합니다. 서브 쉘에서 일부 구성을 시도하여 오류가 발생하는지 확인하면 대부분의 기능을 테스트 할 수 있습니다.


서브 쉘을 사용할 때 아무런 차이가 없습니다. 여전히 ${.sh.version}조정할 수없는 구문 오류로 처리 됩니다. 내가받는 메시지는 bad substitution입니다.
— Sildoreth

@sil 서브 쉘을 사용하는 것은 오류를 잡아내는 것입니다. /dev/null종료 상태로 오류를 리디렉션 하고 무시하십시오.
— Gilles 'SO- 악마 그만

당신이 무슨 말을하는지 이해합니다. 내가 말하는 것은 오류가 리디렉션되지 않는다는 것입니다. 그것은 항상 콘솔에 인쇄합니다. 나는 이것을 Solaris, AIX, HP-UX에서 시도했다. ksh는이 동작을 모두 보여줍니다.
— Sildoreth

@Sildoreth Ah. 나는 Linux에서만 테스트했으며 지금 테스트 할 OS가 없습니다. eval '_sh_version=$(echo "${.sh.version}")' 2>/dev/null더 잘 작동 합니까 ?
— Gilles 'SO- 악마 그만해'

조금 나아 졌어요. Solaris 및 HP-UX에서 제대로 작동합니다. AIX의 경우 명령 행에서 작동하지만 쉘 기능에 배치하려고하면 흥미롭게 다시 시작됩니다.
— Sildoreth

6

KSH_VERSIONksh93버전 93t 이전 에는 구현되지 않았습니다 . 그것은에서 설정됩니다 mksh, pdksh, lksh. 의 버전을 확인하기 ksh위해 다음 단계를 시도해 볼 수 있습니다.

이를 염두에두고 다음과 같이하겠습니다.

case "$KSH_VERSION" in
  (*MIRBSD*|*PD*|*LEGACY*) printf '%s\n' "$KSH_VERSION" ;;
  (*) [ -z "$ERRNO" ] && printf '%s\n' "${.sh.version}" || echo ksh88/86 ;;
esac

$KSH_VERSION공백이 아닌 경우이 검사를 수행하지 않는 이유는 무엇 입니까? 내 우분투 컴퓨터에서 "ksh93"이 인쇄되지만 KSH_VERSION설정되어 있습니다.
— Sildoreth

이전에 실행 된 일부 코드 (예 : .kshrc)가 임의의 값으로 KSH_VERSION 변수를 변경 한 경우 실패합니다.
— jlliagre

@jlliagre : 아니요, 스크립트로 실행되었으므로 읽지 않습니다 .kshrc.
— cuonglm

경우 ENV변수 설정 (일반적으로이 설정되어 ~/.kshrc), 스크립트는 확실히 읽을 .kshrc파일을. 물론 스크립트가 가짜 KSH_VERSION을 설정하는 것은 매우 이상하지만 그럼에도 불구하고 첫 번째 줄에 지정된 것과 다른 인터프리터를 사용하여 스크립트를 명시 적으로 실행하는 것이 가능한 상황과 마찬가지로 이것이 가능합니다.
— jlliagre

@jlliagre : 당신이 그것을 바꿀 수 있다고해도, 참조 할 때 segfault를 얻을 것 KSH_VERSION입니다. 그리고에 mksh, pdksh, lksh, KSH_VERSION읽기 전용으로 표시됩니다.
— cuonglm 2016 년

5

"실제" ksh릴리스 (예 : AT & T 기반)의 경우이 명령을 사용합니다.

strings /bin/ksh | grep Version | tail -2 

내가 얻는 다양한 출력은 다음과 같습니다.

원래 ksh :

@(#)Version M-11/16/88i

dtksh;

@(#)Version 12/28/93
Version not defined

현대 ksh93 :

@(#)$Id: Version AJM 93u+ 2012-08-01 $

들어 pdksh/ msh ksh클론과 현대 AT & T ksh도 버전, 여기에 뭔가입니다 작동하는지 :

$ mksh -c 'echo $KSH_VERSION'
@(#)MIRBSD KSH R50 2015/04/19

편집하다:

테스트 된 ksh 바이너리의 경로를 모르는 것이 아니라 스크립트 내부에서 수행하는 것에 대해 질문하는 것을 간과했습니다.

ksh지원되는 기능이 아니라 사용 된 버전을 실제로 원한다고 가정하면 strings최소한 Linux 및 Solaris에서 작동해야하는 명령 만 사용하여 수행 할 수있는 한 가지 방법이 있습니다 .

echo $(for i in $(find /proc/$$ ! -type d ! -name "pagemap" | 
  grep -v "/path/" | grep -v "/fd/" ) ; do
  strings $i | egrep "([V]ersion|[K]SH_VERSION).*[0-9]" | sort -u
done 2>/dev/null)

이 방법은 /proc마운트되지 않을 수 있으므로 신뢰할 수 없으며 다른 약점이 있습니다. 다른 Unix OS에서는 테스트되지 않았습니다.


이것은 데비안 제시 lksh와 구별되지 않습니다 pdksh.
— cuonglm

@cuonglm 테스트 할 Jessie가 없습니다. 당신은 의미합니까 lksh와 pdksh자신의에서 밖으로 정렬 할 수 없습니다 KSH_VERSION?
— jlliagre

아뇨 strings. KSH_VERSION확실히 할 수 있습니다.
— cuonglm

@cuonglm 내가 확실하지 않으면 죄송합니다. 내가« "진짜"를 썼을 때 ksh릴리스», 내가 명시 적으로 같은 비 AT & T KSH 클론을 제외하고 pdksh, mksh하고 lksh.
— jlliagre

strings일부 ksh 바이너리에서 실행 하는 것은 좋지 않은 생각입니다. 스크립트를 실행하는 것인지 알 수 없기 때문입니다. 아마 스크립트에 의해 실행되고 /usr/local/bin/ksh또는 /home/bob/bin/ksh또는 /bin/sh또는 /usr/posix/bin/sh또는 ...
— 질 'SO-정지되는 악'

2

내가 스크립트를 위해 쓰는 동안 ksh, 나는 것으로 나타났습니다 -aKSH의 옵션이 내장되어있어 whence명령이 나타납니다 이전 버전에서 지원되지 않을에 ksh. 그리고 이것은 제가 확인한 모든 시스템 (Solaris, AIX, HP-UX 및 Linux 포함)에서 사실로 보입니다.

ksh 함수로서의 해결책은 다음과 같습니다.

is_modern_ksh() {
  if whence -a whence > /dev/null 2>&1 ; then
    return 0 #success -> true
  fi
  #Else the call to `whence` failed because `-a` is not supported
  return 1 #failure -> false
}

사용 방법은 다음과 같습니다.

if is_modern_ksh ; then
  echo "You're using a MODERN version of ksh. :)"
else
  echo "You're using an OLD version of ksh. :("
fi

왜 사용하지 ${.sh.version}않습니까?
— cuonglm

@cuonglm 수 없기 때문에. Gilles의 답변 에 대한 의견을 참조하십시오 .
— Sildoreth

불행히도 whencezsh을의가있다-a
— 그렉 A. 우즈

@ GregA.Woods,이 기능은 특별히 ksh를위한 것입니다. 함수 정의는 .kshrc에 들어가므로 zsh와 같은 다른 쉘에는 존재하지 않습니다. zsh에는 whenceksh 또는 그 버전과 관련이없는 자체 내장 명령이 있습니다. ksh가 zsh 인스턴스 내에서 이전 버전인지 확인 해야하는 이유조차 모르겠습니다. 이는 완전히 다른 쉘입니다.
— Sildoreth

가정에 문제가 있습니다 : Zsh는 종종 /bin/ksh데비안 리눅스 와 같은 링크로 설치됩니다 . 이제는 거기에서 사용하지 않으며 (현재 로그인 셸을 변경하여 확인할 수는 없습니다) 읽었는지 여부를 알지 .kshrc못하지만 의심합니다.
— Greg A. Woods

1

CTRL+ ALT+V

또는

ESC, CTRL+V

사용중인 KSH 버전을 대화식으로 결정하는 한 일반적으로 매우 신뢰할 수있는 것으로 입증되었지만 스크립팅이 더 어려워졌습니다.


1
이것은 AIX ksh 88f 버전에서 작동 한 유일한 것입니다.
— Jeff Schaller

1
set -o vi키 바인딩을 생생하게 설정 한 후에 <kbd> ESC </ kbd>, <kbd> CTRL </ kbd> + <kbd> V </ kbd> 옵션이 작동했습니다 . 그 전에 또는 + o vi 또는 -o emacs를 사용하면 나에게 표시되지 않습니다. PDKSH v5.2.14 99 / 07 / 13.2 on openbsd 6.1
— bgStack15

0

$ {. sh.version} 사용의 근본적인 문제는 종료 코드가 0이 아닌 ksh88이 중지된다는 것입니다.

따라서 내 솔루션은 $ {. sh.version}을 참조하는 코드를 하위 셸에 넣은 다음 하위 셸이 0이 아닌 것으로 종료되는지 확인하고 하위 셸에 코드가 포함되어 있는지 확인하는 것입니다. $ {. sh.version}을 참조하는 ksh가 작동합니다. 최종 호출이 true를 확인하도록 리턴 코드를 반대로하는 다른 함수에 의해 호출 된 함수로 랩핑하십시오.

function is_oldksh
{
    (test -n ${.sh.version}) 2>/dev/null
}

function oldkshtest
{

    is_oldksh || return 0 && return 1
}

oldkshtest && echo "old ksh" || echo "new ksh"

ksh88, ksh93 및 pdksh와 함께 AIX 및 Oracle Enterprise Linux 5 및 6에서 이것을 실행했습니다.

피트


1
현대 AT & T은 Ksh 여전히 공급 .sh.version(실제로 KSH_VERSION그것을 효과적으로 별칭입니다). 또한 NetBSD sh와 같은 일부 쉘은 발생 후 읽기를 중지 ${.sh.version}하고 리디렉션이 많지 않아 스크립트를 계속 실행할 수 없습니다.
— 그렉 A. 우즈

0

다음은 실제 원래 Bourne 셸을 아직 테스트하지는 않았지만 이전 ksh88e 및 거의 모든 일반적인 Ksh 클론 (각 버전마다 하나만 있음)을 포함하여 테스트 한 모든 셸에서 합리적으로 잘 작동하는 것 같습니다. test이전 버전에 맞게 표현식을 수정해야 할 수도 있습니다 ....

추가:

나는 또한 외부 (보다 현대적인) test프로그램을 가지고 있지만 Heirloom Bourne Shell에서이를 성공적으로 테스트했습니다 .

is_attksh()
{
    # ksh93
    _sh_version=$(eval 'echo "${.sh.version}"' 2>/dev/null)
    # pdksh only
    _opt_login=$(set -o | grep login)

    test -n "${_sh_version}" -o \( -z "${_opt_login}" -a -n "${_}" -a -n "${ERRNO}" -a -n "${FCEDIT}" -a -n "${PS3}" \)
}
is_attksh && echo "AT&T Ksh${_sh_version:+: }${_sh_version:- (probably ksh88 or ksh86)}" || echo "not real ksh"

is_zsh()
{
    test -n "${ZSH_VERSION}"
}
is_zsh && echo "Zsh: ${ZSH_VERSION}" || echo "not zsh"

ksh가 아닌 쉘에 대해이 기능을 실행하려는 이유는 무엇입니까? bash 또는 zsh에서 스크립트를 실행하는 경우 ksh가 작동하지 않습니다. 또한 ${.sh.version}특정 구문의 ksh 버전 (원래 게시물이 염려 한 버전)이 해당 구문에 치명적인 오류를 발생시키기 때문에 솔루션의 일부가 될 수없는 다른 사람들의 답변을 통해 이미 확립되었습니다 .
— Sildoreth

내가 말했듯이, 내가 보여주는 기능은 "치명적인"오류를 발생시키는 ksh 버전과 동일하게 작동하는 Ash 버전으로 테스트되었습니다.
— Greg A. Woods

내가 작성한 스크립트는 이식성이 있고 가능한 모든 쉘에서 실행되도록 고안되었습니다. 또한 다른 곳에서 말했듯이 일부 사람들은 'ksh'를 입력하면 Zsh 바이너리가 호출되기 때문에 (arkv [0]을 "ksh"로) Zsh를 Ksh로 사용하고 있다는 것을 반드시 알 필요는 없습니다.
— Greg A. Woods

그것은 당신이 어디에서 왔는지 밝힙니다. 그러나 이것은 비현실적인 요구 사항처럼 들립니다. 일반적으로 유닉스 개발자가 "휴대용"이라고 말하면 "이 코드는 어떤 쉘 에서도 실행된다"는 의미는 아니며 " 모든 시스템에서 실행된다"는 의미 입니다. 그리고 다른 쉘을 위해 작성된 스크립트를 실행해야한다면, 그것은 완전히 합법적입니다. 스크립트에서 다른 쉘의 비 대화식 인스턴스를 시작하십시오. 나는 좋은 코딩 관행을 장려하기 때문에 이것을 제기합니다. 이 솔루션이 효과가 있다면 좋습니다. 그러나 나는 다른 사람들에게 더 간단한 접근을 권유합니다.
— Sildoreth

1
이전 버전과의 호환성을 과거로 끌어 올리려는 노력은 어리석은 일입니다. 나는 고대 AT & T Ksh와 Unix Sh 버전을 컴파일하여 일부 기능의 역사와 진화를 더 잘 이해하고 일이 어땠는지에 대한 기억을 새롭게하고 싶다는 개인적인 소망을 만족시켰다. "때때로 그들은 훨씬 더 나빴지 만)"
— Greg A. Woods
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.