Como superar uma incompatibilidade entre o ksh no Linux vs.instalado no AIX/Solaris/HPUX?
Pergunta
Estou envolvido no processo de portabilidade de um sistema contendo centenas de scripts ksh do AIX, Solaris e HPUX para Linux.Me deparei com a seguinte diferença na forma como o ksh se comporta nos dois sistemas:
#!/bin/ksh
flag=false
echo "a\nb" | while read x
do
flag=true
done
echo "flag = ${flag}"
exit 0
No AIX, Solaris e HPUX a saída é "flag = true" no Linux a saída é "flag = false".
Minhas perguntas são:
- Existe uma variável de ambiente que eu posso definir para fazer com que o KSH do Linux se comporte como o outro sistema operacional?Falhando naquilo:
- Existe uma opção no ksh do Linux para obter o comportamento necessário?Falhando naquilo:
- Existe uma implementação ksh disponível para Linux com o comportamento desejado?
Outras notas:
- No AIX, Solaris e HPUX ksh é uma variante do ksh88.
- No Linux, ksh é o domínio público ksh (pdksh)
- No AIX, Solaris e HPUX dtksh e ksh93 (onde os tenho instalados) são consistentes com ksh
- Os sistemas Windows NT aos quais tenho acesso:Cygwin e MKS NT são consistentes com Linux.
- No AIX, Solaris e Linux, o bash é consistente, fornecendo o resultado incorreto (da minha perspectiva) de "flag = false".
A tabela a seguir resume os sistemas do problema:
uname -s uname -r which ksh ksh version flag =
======== ======== ========= =========== ======
Linux 2.6.9-55.0.0.0.2.ELsmp /bin/ksh PD KSH v5.2.14 99/07/13.2 false
AIX 3 /bin/ksh Version M-11/16/88f true // AIX 5.3
/bin/ksh93 Version M-12/28/93e true
SunOS 5.8, 5.9 and 5.10 /bin/ksh Version M-11/16/88i true
/usr/dt/bin/dtksh Version M-12/28/93d true
HP-UX B.11.11 and B.11.23 /bin/ksh Version 11/16/88 true
/usr/dt/bin/dtksh Version M-12/28/93d true
CYGWIN_NT-5.1 1.5.25(0.156/4/2) /bin/ksh PD KSH v5.2.14 99/07/13.2 false
Windows_NT 5 .../mksnt/ksh.exe Version 8.7.0 build 1859... false // MKS
Atualizar
Após alguns conselhos de pessoas da minha empresa, decidimos fazer a seguinte modificação no código.Isso nos dá o mesmo resultado, seja usando os ksh "reais" (ksh88, ksh93) ou qualquer um dos clones ksh (pdksh, MSK ksh).Isso também funciona corretamente com o bash.
#!/bin/ksh
echo "a\nb" > junk
flag=false
while read x
do
flag=true
done < junk
echo "flag = ${flag}"
exit 0
Obrigado a jj33 pela resposta aceita anteriormente.
Solução 2
Após alguns conselhos de pessoas da minha empresa, decidimos fazer a seguinte modificação no código.Isso nos dá o mesmo resultado, seja usando os ksh "reais" (ksh88, ksh93) ou qualquer um dos clones ksh (pdksh, MSK ksh).Isso também funciona corretamente com o bash.
#!/bin/ksh
echo "a\nb" > junk
flag=false
while read x
do
flag=true
done < junk
echo "flag = ${flag}"
exit 0
Obrigado a jj33 pela resposta aceita anteriormente.
Outras dicas
Em vez de usar o pdksh no Linux, use o ksh "real" de kornshell.org.pdksh é uma reimplementação cega do ksh.kornshell.org é o shell korn original que data de cerca de 25 anos (aquele escrito por David Korn).AIX e Solaris usam versões do ksh original, portanto a versão kornshell.org geralmente está completa com recursos e bugs.Tendo começado a usar o SunOS/Solaris, instalar o kornshell.org ksh geralmente é uma das primeiras coisas que faço em uma nova máquina Linux ...
Instalei 'ksh' e 'pdksh' no meu sistema Ubuntu Hardy local.
ii ksh 93s+20071105-1 The real, AT&T version of the Korn shell
ii pdksh 5.2.14-21ubunt A public domain version of the Korn shell
ksh tem o comportamento "correto" que você espera, enquanto o pdksh não.Você pode verificar o repositório de software da sua distribuição Linux local para obter um ksh "real", em vez de usar o pdksh.Os sistemas operacionais "Real Unix" instalarão a versão AT&T do shell Korn, em vez de pdksh, por padrão, sendo eles baseados no AT&T Unix (System V) :-).
A razão para as diferenças é se o bloco interno é executado no contexto original do shell ou em um subshell.Você pode controlar isso com os comandos de agrupamento () e {}.Usar um arquivo temporário, como você faz na atualização, funcionará na maioria das vezes, mas terá problemas se o script for executado duas vezes rapidamente ou se for executado sem limpar o arquivo, etc.
#!/bin/ksh
flag=false
echo "a\nb" | { while read x
do
flag=true
done }
echo "flag = ${flag}"
exit 0
Isso pode ajudar com o problema que você estava enfrentando no Linux ksh.Se você usar parênteses em vez de colchetes, obterá o comportamento do Linux nas outras implementações do ksh.
Aqui está outra solução para o problema de eco " "
Passos:
- Encontre o nome do pacote ksh
$ rpm -qa --queryformat "%{NAME}-%{VERSION}-%{RELEASE}(%{ARCH})\n" | grep "ksh"
ksh-20100621-19.el6_4.3(x86_64)
desinstalar ksh
$ sudo yum remove ksh-20100621-19.el6_4.3.x86_64
baixe pdksh-5.2.14-37.el5_8.1.x86_64.rpm (verifique o sistema operacional para 32 ou 64 bits e escolha o pacote correto)
Instale pdksh-5.2.14-37.el5_8.1.x86_64.rpm
$ sudo yum -y install /SCRIPT_PATH/pdksh-5.2.14-37.el5_8.1.x86_64.rpm
Saída antes da instalação do PDKSH
$ ora_db_start_stop.sh
\n==============
Usage: START
==============\n\n
./ora_db_start_stop.sh START ALL \n
OR \n
./ora_db_start_stop.sh START ONE_OR_MORE \n
\n==============
Usage: STOP
==============\n\n
./ora_db_start_stop.sh STOP ALL \n
OR \n
./ora_db_start_stop.sh STOP ONE_OR_MORE \n\n
Após a instalação do PDKSH
==============
Uso:COMEÇAR
./ora_db_start_stop.sh START ALL
OU
./ora_db_start_stop.sh START ONE_OR_MORE
==============
Uso:PARAR
./ora_db_start_stop.sh STOP ALL
OU
./ora_db_start_stop.sh STOP ONE_OR_MORE
Não conheço nenhuma opção específica para forçar o ksh a ser compatível com uma versão mais antiga específica.Dito isto, talvez você possa instalar uma versão muito antiga do ksh em sua caixa Linux e fazer com que ela se comporte de maneira compatível?
Pode ser mais fácil instalar uma versão mais moderna do shell amy nas caixas AIX/HP-UX e apenas migrar seus scripts para usar sh.Eu sei que existem versões do bash disponíveis para todas as plataformas.
Seu script fornece a saída correta (verdadeira) quando zsh
é usado com o emulate -L ksh
opção.Se tudo mais falhar, você pode tentar usar zsh
no Linux.
Você tem que ficar dentro de ksh?
Mesmo se você usar o mesmo ksh, você ainda chamará todos os tipos de comandos externos (grep, ps, cat, etc...), parte deles terá parâmetros diferentes e saídas diferentes de sistema para sistema.Você terá que levar em conta essas diferenças ou usar a versão GNU de cada uma delas para tornar as coisas iguais.
O Perl A linguagem de programação foi originalmente projetada exatamente para superar esse problema.Ele inclui todos os recursos que um programador do UNIX Shell gostaria do programa de shell, mas é o mesmo em todos os sistemas Unix.Você pode não ter a versão mais recente em todos esses sistemas, mas se precisar instalar algo, talvez seja melhor instalar o Perl.