¿Cómo superar una incompatibilidad entre el ksh en Linux y el que está instalado en AIX/Solaris/HPUX?
(8)
Estoy involucrado en el proceso de portar un sistema que contiene varios cientos de scripts ksh de AIX, Solaris y HPUX a Linux. He encontrado la siguiente diferencia en la forma en que ksh se comporta en los dos sistemas:
#!/bin/ksh
flag=false
echo "a/nb" | while read x
do
flag=true
done
echo "flag = ${flag}"
exit 0
En AIX, Solaris y HPUX, la salida es "flag = true" en Linux y la salida es "flag = false".
Mis preguntas son:
- ¿Hay alguna variable de entorno que pueda configurar para que el ksh de Linux se comporte como el otro Os? Fallando en eso:
- ¿Hay una opción en el ksh de Linux para obtener el comportamiento requerido? Fallando en eso:
- ¿Hay una implementación de ksh disponible para Linux con el comportamiento deseado?
Otras notas:
- En AIX, Solaris y HPUX ksh es una variante de ksh88.
- En Linux, ksh es el dominio público ksh (pdksh)
- En AIX, Solaris y HPUX dtksh y ksh93 (donde los tengo instalados) son consistentes con ksh
- Los sistemas Windows NT a los que tengo acceso: Cygwin y MKS NT, son consistentes con Linux.
- En AIX, Solaris y Linux, bash es coherente, dando el resultado incorrecto (desde mi perspectiva) de "flag = false".
La siguiente tabla resume los sistemas del 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
Actualizar
Después de algunos consejos de personas de mi compañía, decidimos realizar la siguiente modificación al código. Esto nos da el mismo resultado si usamos el ksh "real" (ksh88, ksh93) o cualquiera de los clones ksh (pdksh, MSK ksh). Esto también funciona correctamente con bash.
#!/bin/ksh
echo "a/nb" > junk
flag=false
while read x
do
flag=true
done < junk
echo "flag = ${flag}"
exit 0
Gracias a jj33 por la respuesta previamente aceptada.
¿Tienes que quedarte dentro de ksh?
Incluso si usa el mismo ksh, seguirá llamando a todo tipo de comandos externos (grep, ps, cat, etc.). Parte de ellos tendrán diferentes parámetros y diferentes resultados de sistema a sistema. O bien, tendrá que tener en cuenta esas diferencias o utilizar la versión GNU de cada una de ellas para que todo sea igual.
El lenguaje de programación Perl originalmente fue diseñado exactamente para superar este problema. Incluye todas las características que un programador de shell unix querría del programa shell pero es igual en todos los sistemas Unix. Puede que no tenga la última versión en todos esos sistemas, pero si necesita instalar algo, tal vez sea mejor instalar Perl.
Aquí está la otra solución para el problema del eco "/ n"
Pasos:
- Encuentra el nombre del paquete 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
down load pdksh-5.2.14-37.el5_8.1.x86_64.rpm (Compruebe el sistema operativo para 32 bits o 64 bits y elija el paquete correcto)
Instalar 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
Salida antes de instalar 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
Después de instalar PDKSH
==============
Uso: INICIO
./ora_db_start_stop.sh START ALL
O
./ora_db_start_stop.sh START ONE_OR_MORE
==============
Uso: PARE
./ora_db_start_stop.sh STOP ALL
O
./ora_db_start_stop.sh STOP ONE_OR_MORE
Después de algunos consejos de personas de mi compañía, decidimos realizar la siguiente modificación al código. Esto nos da el mismo resultado si usamos el ksh "real" (ksh88, ksh93) o cualquiera de los clones ksh (pdksh, MSK ksh). Esto también funciona correctamente con bash.
#!/bin/ksh
echo "a/nb" > junk
flag=false
while read x
do
flag=true
done < junk
echo "flag = ${flag}"
exit 0
Gracias a jj33 por la respuesta aceptada anterior.
El motivo de las diferencias es si el bloque interno se ejecuta en el contexto del shell original o en una subcadena. Es posible que pueda controlar esto con los comandos de agrupamiento () y {}. Usar un archivo temporal, como lo hace en su actualización, funcionará la mayor parte del tiempo, pero se encontrará con problemas si el script se ejecuta dos veces rápidamente, o si se ejecuta sin borrar el archivo, etc.
#!/bin/ksh
flag=false
echo "a/nb" | { while read x
do
flag=true
done }
echo "flag = ${flag}"
exit 0
Eso puede ayudar con el problema que estaba recibiendo en el ksh de Linux. Si usa paréntesis en lugar de llaves, obtendrá el comportamiento de Linux en las otras implementaciones de ksh.
En lugar de usar pdksh en Linux, use el ksh "real" de kornshell.org. pdksh es una reimplementación ciega de ksh. kornshell.org es el caparazón korn original que data de hace 25 años aproximadamente (el escrito por David Korn). AIX y Solaris usan versiones del ksh original, por lo que la versión de kornshell.org suele ser completa y completa. Habiendo cortado los dientes con SunOS / Solaris, la instalación de kornshell.org ksh suele ser una de las primeras cosas que hago en una nueva caja de Linux ...
Instalé ''ksh'' y ''pdksh'' en mi 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 tiene el comportamiento "correcto" que está esperando mientras que pdksh no lo hace. Puede verificar el repositorio de software de su distribución local de Linux para obtener un ksh "real", en lugar de usar pdksh. Los sistemas operativos "Real Unix" van a instalar la versión de AT & T del shell Korn, en lugar de pdksh, de forma predeterminada, con lo que se basan en AT & T Unix (System V) :-).
No conozco ninguna opción particular para forzar que ksh sea compatible con una versión anterior particular. Dicho esto, ¿quizás podrías instalar una versión muy antigua de ksh en tu linux box y hacer que se comporte de manera compatible?
Puede ser más fácil instalar una versión más moderna de amy shell en los cuadros AIX / HP-UX, y simplemente migrar los scripts para usar sh. Sé que hay versiones de bash disponibles para todas las plataformas.
Su script proporciona el resultado correcto (verdadero) cuando se usa zsh
con la opción emulate -L ksh
. Si todo lo demás falla, puede intentar usar zsh
en Linux.