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가 없습니다. 당신은 의미합니까 lkshpdksh자신의에서 밖으로 정렬 할 수 없습니다 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.