El shell C ( csh o la versión mejorada, tcsh ) es un shell Unix creado por Bill Joy mientras era estudiante de posgrado en la Universidad de California, Berkeley, a finales de los años 1970. Se ha distribuido ampliamente, comenzando con la versión 2BSD de Berkeley Software Distribution (BSD), que Joy distribuyó por primera vez en 1978. [2] [3] Otros contribuyentes tempranos a las ideas o al código fueron Michael Ubell, Eric Allman , Mike O. 'Brien y Jim Kulp. [4]
El shell C es un procesador de comandos que normalmente se ejecuta en una ventana de texto, lo que permite al usuario escribir y ejecutar comandos. El shell C también puede leer comandos de un archivo, llamado script . Como todos los shells de Unix, admite comodines en nombres de archivos , tuberías , aquí documentos , sustitución de comandos , variables y estructuras de control para pruebas de condiciones e iteraciones . Lo que diferenciaba al C shell de los demás, especialmente en la década de 1980, eran sus características interactivas y su estilo general. Sus nuevas funciones hicieron que su uso fuera más fácil y rápido. El estilo general del lenguaje se parecía más a C y se consideraba más legible.
En muchos sistemas, como macOS y Red Hat Linux , csh es en realidad tcsh , una versión mejorada de csh. A menudo, uno de los dos archivos es un enlace físico o un enlace simbólico al otro, de modo que cualquiera de los nombres se refiere a la misma versión mejorada del shell C. El código fuente original de csh y el binario son parte de NetBSD .
En Debian y algunos derivados (incluido Ubuntu ), existen dos paquetes diferentes: csh y tcsh. El primero está basado en la versión BSD original de csh [5] [6] y el segundo es el tcsh mejorado. [7] [8]
tcsh agregó conceptos de edición de línea de comando y finalización de comando y nombre de archivo tomados del sistema Tenex , que es la fuente de la "t". [9] Debido a que solo agregó funcionalidad y no cambió lo que ya existía, tcsh siguió siendo compatible con versiones anteriores [10] con el shell C original. Aunque comenzó como una rama lateral del árbol fuente original que Joy había creado, tcsh es ahora la rama principal para el desarrollo continuo. tcsh es muy estable, pero siguen apareciendo nuevas versiones aproximadamente una vez al año, que consisten principalmente en correcciones de errores menores. [11]
Los principales objetivos de diseño para el shell C eran que debería parecerse más al lenguaje de programación C y que debería ser mejor para uso interactivo.
El sistema Unix había sido escrito casi exclusivamente en C, por lo que el primer objetivo del shell C era un lenguaje de comando que fuera estilísticamente más consistente con el resto del sistema. Las palabras clave, el uso de paréntesis y la gramática de expresión incorporada del shell C y el soporte para matrices estuvieron fuertemente influenciados por C.
Según los estándares actuales, C Shell puede no parecer particularmente más parecido a C que muchos otros lenguajes de programación populares. Pero durante los años 80 y 90, la diferencia se consideró sorprendente, particularmente en comparación con Bourne shell (también conocido como sh ), el entonces dominante shell escrito por Stephen Bourne en Bell Labs . Este ejemplo ilustra la sintaxis y los operadores de expresión más convencionales del shell C.
concha de bourne
#!/bin/sh if [ $days -gt 365 ] then echo Esto es más de un año. fi
caparazón C
#!/bin/csh if ( $days > 365 ) then echo Esto es más de un año. endif
El pez Bourne carecía de una gramática de expresión . La condición entre corchetes tuvo que evaluarse mediante el medio más lento de ejecutar el programa de prueba externo . El comando de sh if
tomó sus palabras de argumento como un nuevo comando para ejecutarse como un proceso secundario . Si el niño salía con un código de retorno cero , sh buscaría una then
cláusula (una declaración separada, pero a menudo escrita unida en la misma línea con un punto y coma) y ejecutaría ese bloque anidado. De lo contrario, ejecutaría el else. Vincular el programa de prueba como " test
" y " [
" dio la ventaja de notación de los corchetes y la apariencia de que la funcionalidad de la prueba era parte del lenguaje sh. El uso por parte de sh de una palabra clave invertida para marcar el final de un bloque de control fue un estilo tomado de ALGOL 68 . [12]
Por el contrario, csh podía evaluar la expresión directamente, lo que la hacía más rápida. También reivindicaba una mejor legibilidad: sus expresiones utilizaban una gramática y un conjunto de operadores copiados en su mayoría de C, ninguna de sus palabras clave estaba invertida y el estilo general también se parecía más a C.
Aquí hay un segundo ejemplo, comparando guiones que calculan las primeras 10 potencias de 2.
concha de bourne
#!/bin/sh i = 2 j = 1 while [ $j -le 10 ] do echo '2 **' $j = $i i = ` expr $i '*' 2 ` j = ` expr $j + 1` hecho
caparazón C
#!/bin/csh set i = 2 set j = 1 while ( $j < = 10 ) echo '2 **' $j = $i @ i * = 2 @j++fin
Nuevamente, debido a la falta de una gramática de expresión, el script sh usa sustitución de comandos y el comando expr . ( El shell POSIX moderno tiene esa gramática: la declaración podría escribirse i=$((i * 2))
o : "$((i *= 2))"
.)
Finalmente, aquí hay un tercer ejemplo, que muestra los diferentes estilos para una declaración de cambio .
concha de bourne
#!/bin/sh para i en d* ¿ caso $i en d? ) echo $i es corto ;; * ) echo $i es largo ;; esac hecho
caparazón C
#!/bin/csh foreach i ( d* ) switch ( $i ) case d?: echo $i es un descanso corto predeterminado : echo $i es un extremo largo
En el script sh, " ;;
" marca el final de cada caso porque, de lo contrario, sh no permite declaraciones nulas.
El segundo objetivo era que el shell C debería ser mejor para uso interactivo. Introdujo numerosas características nuevas que hicieron que su uso fuera más fácil, rápido y amigable al escribir comandos en una terminal. Los usuarios podían hacer las cosas con muchas menos pulsaciones de teclas y funcionaba más rápido. Las más importantes de estas nuevas características fueron los mecanismos de edición e historial, alias, pilas de directorios, notación de tilde, cdpath, control de trabajos y hash de rutas. Estas nuevas características resultaron muy populares y desde entonces muchas de ellas han sido copiadas por otros shells de Unix.
El historial permite a los usuarios recuperar comandos anteriores y volver a ejecutarlos escribiendo sólo unas pocas teclas rápidas. Por ejemplo, escribir dos signos de exclamación (" !!
") [13] como comando hace que se ejecute el comando inmediatamente anterior. Otras combinaciones cortas de teclas, por ejemplo, " !$
" (que significa "el argumento final del comando anterior"), permiten pegar fragmentos de comandos anteriores y editarlos para formar un nuevo comando.
La edición se puede realizar no sólo en el texto de un comando anterior, sino también en sustituciones de variables. Los operadores van desde una simple búsqueda/reemplazo de cadenas hasta el análisis de un nombre de ruta para extraer un segmento específico.
Los alias permiten al usuario escribir el nombre de un alias y hacer que el shell C lo expanda internamente en cualquier conjunto de palabras que el usuario haya definido. Para muchas situaciones simples, los alias se ejecutan más rápido y son más convenientes que los scripts.
La pila de directorios permite al usuario insertar o abrir el directorio de trabajo actual , lo que facilita el salto hacia adelante y hacia atrás entre diferentes lugares en el sistema de archivos.
La notación tilde ofrece una forma abreviada de especificar nombres de rutas relativas al directorio de inicio utilizando el ~
carácter " ".
La tecla de escape se puede utilizar de forma interactiva para mostrar posibles terminaciones de un nombre de archivo al final de la línea de comando actual.
Cdpath extiende la noción de ruta de búsqueda al cd
comando (cambiar directorio): si el directorio especificado no está en el directorio actual , csh intentará encontrarlo en los directorios de cdpath.
Hasta bien entrada la década de 1980, la mayoría de los usuarios sólo tenían terminales en modo de caracteres simples que impedían múltiples ventanas, por lo que sólo podían trabajar en una tarea a la vez. El control de trabajo del shell C permitía al usuario suspender la actividad actual y crear una nueva instancia del shell C, llamada trabajo, escribiendo ^Z
. Luego, el usuario podría alternar entre trabajos usando el fgcomando. Se decía que el trabajo activo estaba en primer plano. Se dijo que otros trabajos estaban suspendidos (detenidos) o ejecutándose en segundo plano .
El hash de ruta acelera la búsqueda de archivos ejecutables por parte del shell C. En lugar de realizar una llamada al sistema de archivos en cada directorio de ruta, uno a la vez, hasta que encuentre el archivo o se quede sin posibilidades, el shell C consulta una tabla hash interna creada escaneando los directorios de ruta. Esa tabla generalmente puede indicarle al shell C dónde encontrar el archivo (si existe) sin tener que buscarlo y se puede actualizar con el rehash
comando.
El shell C opera una línea a la vez. Cada línea se convierte en un conjunto de palabras separadas por espacios u otros caracteres con significado especial, incluidos paréntesis, canalizaciones y operadores de redirección de entrada/salida, punto y coma y símbolos.
Una declaración básica es aquella que simplemente ejecuta un comando. La primera palabra se toma como nombre del comando que se ejecutará y puede ser un comando interno, por ejemplo, echo
o un comando externo. El resto de las palabras se pasan como argumentos del comando.
A nivel de declaración básica, estas son algunas de las características de la gramática:
El shell C, como todos los shells de Unix, trata cualquier argumento de línea de comandos que contenga caracteres comodín como un patrón y lo reemplaza con la lista de todos los nombres de archivos que coinciden (consulte globbing ).
*
coincide con cualquier número de caracteres.?
coincide con cualquier carácter individual.[
... ]
coincide con cualquiera de los caracteres dentro de los corchetes. Se permiten rangos, utilizando el guión.[^
... ]
coincide con cualquier personaje que no esté en el conjunto.El shell C también introdujo varias comodidades de notación (a veces conocidas como globbing extendido ), ya que fue copiado por otros shells de Unix.
abc{def,ghi}
es alternancia (también conocida como expansión de llaves ) y se expande a abcdef abcghi .~
significa el directorio de inicio del usuario actual.~user
significa el directorio de inicio del usuario .*/*.c
Se admiten varios comodines a nivel de directorio, por ejemplo " ".
Desde la versión 6.17.01, la opción también admite comodines recursivos al estilo zsh (por ejemplo, " **/*.c
" o " ") .***/*.html
globstar
Darle al shell la responsabilidad de interpretar los comodines fue una decisión importante en Unix. Significaba que los comodines funcionarían con todos los comandos y siempre de la misma manera. Sin embargo, la decisión se basó en la capacidad de Unix para pasar largas listas de argumentos de manera eficiente a través de la llamada al sistema exec que utiliza csh para ejecutar comandos. Por el contrario, en Windows , la interpretación de comodines la realiza cada aplicación de forma convencional. Este es un legado de MS-DOS, que solo permitía pasar una línea de comando de 128 bytes a una aplicación, lo que hacía que el uso de comodines en el símbolo del sistema de DOS no fuera práctico. Aunque el Windows moderno puede pasar líneas de comando de hasta aproximadamente 32 000 caracteres Unicode , la carga de la interpretación de los comodines recae en la aplicación.
De forma predeterminada, cuando csh ejecuta un comando, el comando hereda los identificadores del archivo stdio de csh para stdin , stdout y stderr , que normalmente apuntan a la ventana de la consola donde se ejecuta el shell C. Los operadores de redirección de E/S permiten que el comando utilice un archivo como entrada o salida.
>
file significa que stdout se escribirá en file , sobrescribiéndolo si existe y creándolo si no existe. Los errores siguen apareciendo en la ventana del shell.>&
file significa que tanto stdout como stderr se escribirán en file , sobrescribiéndolo si existe y creándolo si no existe.>>
archivo significa que la salida estándar se agregará al final del archivo .>>&
file significa que tanto stdout como stderr se agregarán al final del archivo .<
file significa que stdin se leerá desde el archivo .<<
La cadena es un documento aquí . Stdin leerá las siguientes líneas hasta la que coincida con la cadena .Redirigir stderr por sí solo no es posible sin la ayuda de un sub-shell.
set filter = "$home" '/filter'
mkfifo ” $filter " cat " $filter " & ( ( ls /root/ || echo Sin acceso. ) > " $filter " ) >& /dev/null
Los sistemas que admiten descriptores de archivos como archivos pueden utilizar la siguiente solución.
( ( ( echo ok ; '' ) > /dev/fd/0 ) >& /dev/null < /dev/fd/1 ) | ( echo "$<" adiós )
Los comandos se pueden unir en la misma línea.
;
significa ejecutar el primer comando y luego el siguiente.&&
significa ejecutar el primer comando y, si tiene éxito con un código de retorno 0 , ejecutar el siguiente.||
significa ejecutar el primer comando y, si falla con un código de retorno distinto de cero, ejecutar el siguiente.Los comandos se pueden conectar mediante una tubería, lo que hace que la salida de un comando pase a la entrada del siguiente. Ambos comandos se ejecutan simultáneamente .
|
significa conectar stdout a stdin del siguiente comando. Los errores siguen apareciendo en la ventana del shell.|&
significa conectar tanto stdout como stderr a stdin del siguiente comando.Ejecutar simultáneamente significa "en paralelo". En un sistema multinúcleo (múltiples procesadores), los comandos canalizados pueden literalmente ejecutarse al mismo tiempo; de lo contrario, el programador del sistema operativo divide el tiempo entre ellos.
Dado un comando, por ejemplo, " a | b
", el shell crea una tubería , luego inicia ambos a
y b
con stdio para los dos comandos redirigidos de modo que a
escribe su salida estándar en la entrada de la tubería mientras b
lee la entrada estándar desde la salida de la tubería. El sistema operativo implementa las canalizaciones con una cierta cantidad de almacenamiento en búfer, de modo que a
se puede escribir durante un tiempo antes de que se llene, pero una vez que se llena, cualquier escritura nueva se bloqueará dentro del sistema operativo hasta que b
se lea lo suficiente para desbloquear nuevas escrituras. Si b
intenta leer más datos de los disponibles, se bloqueará hasta que a
se hayan escrito más datos o hasta que la tubería se cierre, por ejemplo, si a
sale.
Si una palabra contiene un signo de dólar, " $
", los siguientes caracteres se toman como el nombre de una variable y la referencia se reemplaza por el valor de esa variable. Varios operadores de edición, escritos como sufijos de la referencia, permiten editar el nombre de la ruta (por ejemplo, " :e
" para extraer sólo la extensión) y otras operaciones.
Los mecanismos de cotización permiten que caracteres especiales, como espacios en blanco, comodines, paréntesis y signos de dólar, se tomen como texto literal .
\
significa tomar el siguiente carácter como un carácter literal ordinario."
la cadena"
es una comilla débil. Los espacios en blanco y los comodines encerrados se toman como literales, pero aún se realizan sustituciones de variables y comandos.'
cadena'
es una cita fuerte. Toda la cadena adjunta se toma como literal.Las comillas dobles dentro de comillas dobles deben llevar como escape "\""
. Lo mismo se aplica al símbolo del dólar, para evitar la expansión variable "\$"
. Para las comillas invertidas, se requieren comillas simples para evitar el anidamiento de sustitución de comandos "'\`'"
.
La sustitución de comandos permite utilizar la salida de un comando como argumento para otro.
`
comando`
significa tomar el resultado de comando , analizarlo en palabras y pegarlas nuevamente en la línea de comando.El siguiente es un ejemplo de sustituciones de comandos anidados.
echo "`echo " \"\` "echo " \"\\\"\\\`\" "echo " \"\\\"\\\\\\\"\\\\\\\`\ \\"\" "echo " \"\\\"\\\\\\\"\\\\\\\\\\\\\\\"\\\\\\\\\\\\ \\\`\\\\\\\"\\\"\" "echo " \"\\\"\\\\\\\"\\\\\\\\\\\\\\\ "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\`\\\\\\\\\\\\\\\"\ \\\\\\"\\\"\" "pwd" \"\\\"\\\\\\\"\\\\\\\\\\\\\\\"\\\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\`\\\\\\\\\\\\\\\"\\\\\\ \\\\\\\\\`\\\\\\\\\\\\\\\"\\\\\\\"\\\\\\\`\\\\\\\" \\\"\\\`\\\"\"\`\" "`"
Normalmente, cuando el shell C inicia un comando, espera a que finalice antes de darle al usuario otro mensaje que indica que se puede escribir un nuevo comando.
&
significa iniciar el comando en segundo plano y solicitar inmediatamente un nuevo comando.Un subshell es una copia secundaria separada del shell que hereda el estado actual pero luego puede realizar cambios, por ejemplo, en el directorio actual, sin afectar al padre.
(
comandos )
significa ejecutar comandos en un subshell.El shell C proporciona estructuras de control tanto para las pruebas de condición como para la iteración . Las estructuras de control de las pruebas de condición son las declaraciones if y switch. Las estructuras de control de iteración son las declaraciones while, foreach y repetir.
Hay dos formas de declaración if . La forma corta se escribe en una sola línea, pero solo puede especificar un comando si la expresión es verdadera.
comando si ( expresión )
El formato largo utiliza las palabras clave then, else y endif para permitir que se anidan bloques de comandos dentro de la condición.
si ( expresión1 ) entonces ordena else si ( expresión2 ) entonces ordena ...demás comandos endif
Si las palabras clave else y if aparecen en la misma línea, csh las encadena, en lugar de anidarlas; el bloque termina con un único endif.
La declaración de cambio compara una cadena con una lista de patrones, que pueden contener caracteres comodín. Si no hay nada que coincida, se toma la acción predeterminada, si la hay.
cambiar ( cadena ) patrón de caso 1: comandos patrón de caso breaksw2 : comandos rompe ... por defecto : comandos rompe y termina
La declaración while evalúa una expresión. Si es verdadero, el shell ejecuta los comandos anidados y luego los repite mientras la expresión siga siendo verdadera.
mientras ( expresión ) comandosfin
La instrucción foreach toma una lista de valores, generalmente una lista de nombres de archivos generados mediante comodines, y luego, para cada uno, establece la variable de bucle en ese valor y ejecuta los comandos anidados.
variable de bucle foreach ( lista de valores ) comandosfin
La declaración de repetición repite un solo comando un número entero de veces.
repetir comando entero
El shell C implementa variables tanto de shell como de entorno . [14] Las variables de entorno, creadas usando la setenv
declaración, son siempre cadenas simples, pasadas a cualquier proceso hijo , que recupera estas variables a través del envp[]
argumento to main()
.
Las variables del Shell, creadas usando las sentencias set
o @
, son internas del Shell C. No se pasan a procesos secundarios. Las variables de Shell pueden ser cadenas simples o matrices de cadenas. Algunas de las variables del shell están predefinidas y se utilizan para controlar varias opciones internas del shell C, por ejemplo, qué debería suceder si un comodín no coincide con nada.
En las versiones actuales de csh, las cadenas pueden tener una longitud arbitraria, hasta millones de caracteres.
Las variables se pueden ampliar según sea necesario. Sin embargo, si desea trabajar en un tamaño fijo, se prefiere la siguiente sintaxis.
# Crea una variable lo suficientemente grande como para contener 1024 elementos. conjunto fijo = { , }{ , } { , }{ , } { , }{ , }{ , }{ , }{ , }{ , }
El shell C implementa una gramática de expresión de enteros de 32 bits con operadores tomados de C pero con algunos operadores adicionales para comparaciones de cadenas y pruebas de sistemas de archivos, por ejemplo, pruebas de la existencia de un archivo. Los operadores deben estar separados por espacios en blanco de sus operandos. Se hace referencia a las variables como $
nombre .
La precedencia de operadores también se toma prestada de C, pero con diferentes reglas de asociatividad de operadores para resolver la ambigüedad de qué viene primero en una secuencia de operadores de igual precedencia. En C, la asociatividad es de izquierda a derecha para la mayoría de los operadores; en el shell C, es de derecha a izquierda. Por ejemplo,
// C grupos desde la izquierda int i = 10/5 * 2 ; printf ( "%d \n " , i ); // imprime 4 i = 7 - 4 + 2 ; printf ( "%d \n " , i ); // imprime 5 i = 2 >> 1 << 4 ; printf ( "%d \n " , i ); // imprime 16
# Grupos de shell C desde la derecha
@ i = 10/5 * 2 echo $i # imprime 1
@ i = 7 - 4 + 2 echo $i # imprime 1
@ i = ( 2 >> 1 << 4 ) echo $i # impresiones 0
Los paréntesis en el ejemplo del shell C sirven para evitar que los operadores de desplazamiento de bits se confundan con operadores de redirección de E/S. En cualquiera de los idiomas, siempre se pueden utilizar paréntesis para especificar explícitamente el orden de evaluación deseado, aunque sólo sea por motivos de claridad.
Los valores de retorno están limitados a 8 bits. Para exit
expresiones, el operador de negación unario se puede utilizar para evaluaciones de 32 bits.
salida ! ! 256 # Devuelve 1.
Aunque el propio Stephen Bourne reconoció que csh era superior a su shell para uso interactivo, [15] nunca ha sido tan popular para secuencias de comandos.
En 1983, tanto csh como Bourne shell estaban disponibles para el sistema operativo UNOS de Charles River Data Systems , entre otras herramientas UNIX, bajo licencia de Bell Laboratories . [16]
Inicialmente, y durante la década de 1980, no se podía garantizar que csh estuviera presente en todos los sistemas Unix y similares, pero sí sh, lo que lo convertía en una mejor opción para cualquier script que tuviera que ejecutarse en otras máquinas. A mediados de la década de 1990, csh estaba ampliamente disponible, pero el uso de csh para secuencias de comandos enfrentó nuevas críticas por parte del comité POSIX , [17] que especificó que sólo debería haber un shell preferido, el KornShell , tanto para propósitos interactivos como de secuencias de comandos. El shell C también enfrentó críticas de otros [18] [19] por los supuestos defectos de sintaxis, características faltantes y mala implementación del shell C.
set
, setenv
y alias
hacían básicamente lo mismo, es decir, asociar un nombre con una cadena o conjunto de palabras. Pero los tres tenían diferencias leves pero innecesarias. Se requería un signo igual para a set
pero no para setenv
o alias
; se requerían paréntesis alrededor de una lista de palabras para a set
pero no para setenv
o alias
, etc. De manera similar, las construcciones de bucle if
, switch
y utilizan palabras clave innecesariamente diferentes ( endif
, endsw
y end
) para terminar los bloques anidados.Funcionó para la mayoría de los comandos escritos interactivamente, pero para los comandos más complejos que un usuario podría escribir en un script, podría fallar fácilmente y producir solo un mensaje de error críptico o un resultado no deseado. Por ejemplo, el armazón C no podía soportar tuberías entre estructuras de control. Intentar canalizar la salida de un foreach
comando grep
simplemente no funcionó. (La solución, que funciona para muchas de las quejas relacionadas con el analizador, es dividir el código en scripts separados. Si se foreach
mueve a un script separado, la canalización funciona porque los scripts se ejecutan bifurcando una nueva copia de csh eso hereda los identificadores stdio correctos. También es posible dividir códigos en un solo archivo. A continuación se proporciona un ejemplo sobre cómo dividir códigos en un solo archivo).
Otro ejemplo es el comportamiento no deseado en los siguientes fragmentos. Ambos parecen significar: "Si 'miarchivo' no existe, créelo escribiendo 'mitexto' en él". Pero la versión de la derecha siempre crea un archivo vacío porque el orden de evaluación del shell C es buscar y evaluar operadores de redirección de E/S en cada línea de comando a medida que la lee, antes de examinar el resto de la línea para ver si contiene una estructura de control.
# Funciona como se esperaba si ( ! -e miarchivo ) luego echo mitexto > miarchivo endif
# Siempre crea un archivo vacío si ( ! -e miarchivo ) echo mitexto > miarchivo
# Solución alternativa (sólo para tcsh) if ( ! -e myfile ) eval "echo mytext > myfile"
# Segunda solución alternativa (para csh y tcsh) ( exit ( -e myfile ) && ( ( echo mytext > myfile ) >& /dev/null || echo No se puede crear el archivo. ) || echo El archivo existe.
La implementación también es criticada por sus mensajes de error notoriamente deficientes, por ejemplo, "0: Evento no encontrado", que no proporciona ninguna información útil sobre el problema.
Sin embargo, practicando, es posible superar esas deficiencias (instruyendo así al programador a adoptar enfoques mejores y más seguros al implementar un script).
El "0: Evento no encontrado". El error implica que no hay comandos guardados en el historial. Es posible que el historial no funcione correctamente en los scripts, pero tener un conjunto preestablecido de comandos en una variable sirve como solución alternativa.
#!/bin/csh -f set cmdlist = ( 'date # 1' \ 'uname # 2' \ 'tty # 3' \ 'id # 4' ) echo -n 'Ingresa un número para ejecutar un comando del historial : ' set cmdexec = "$<" ( exit ( ! ( "$cmdexec" > 0 && \ "$cmdexec" < = "$#cmdlist" ) ) ) >& /dev/null if ( "$status" ) entonces echo 'Número de evento no válido.' foreach cmd ( $cmdlist :q ) echo "$cmd" end exit -1 endif eval "$cmdlist[$cmdexec]"
Prefiere descifrar códigos recurriendo al script como solución alternativa para las funciones.
#!/bin/csh -f if ( ! "$?main" ) then if ( ! "$?0" ) then echo 'Debes ejecutar este script llamando explícitamente a su archivo.' salir -1 función de alias endif 'set argv = (\!*); fuente "$main"' set main = "$0" set ret = "`función myfunc`" echo "$ret" salir endif ir a "$1" ; cambiomifunc:función mifunc2echo "Una función." salidamifunc2:echo "Otra función." salida
El shell C tuvo mucho éxito al introducir una gran cantidad de innovaciones, incluido el mecanismo de historial, alias, notación de tilde, finalización interactiva de nombres de archivos, una gramática de expresión integrada en el shell y más, que desde entonces han sido copiadas por otros shells de Unix. Pero a diferencia de sh , que ha generado una gran cantidad de clones desarrollados de forma independiente, incluidos ksh y bash , sólo se conocen dos clones de csh. (Dado que tcsh se basó en el código csh escrito originalmente por Bill Joy, no se considera un clon).
En 1986, Allen Holub escribió On Command: Writing a Unix-Like Shell for MS-DOS , [22] un libro que describe un programa que había escrito llamado "SH" pero que de hecho copiaba el diseño del lenguaje y las características de csh, no sh. . Los disquetes complementarios que contenían el código fuente completo para SH y un conjunto básico de utilidades similares a Unix (cat, cp, grep, etc.) estaban disponibles por parte del editor por 25 y 30 dólares, respectivamente. Las estructuras de control, la gramática de expresión, el mecanismo histórico y otras características del SH de Holub eran idénticas a las del shell C.
En 1988, Hamilton Laboratories comenzó a comercializar el shell Hamilton C para OS/2 . [23] Incluía tanto un clon de csh como un conjunto de utilidades similares a Unix. En 1992, se lanzó el shell Hamilton C para Windows NT . [24] La versión de Windows continúa siendo compatible activamente, pero la versión OS/2 se suspendió en 2003. [24] Una referencia rápida de principios de 1990 [25] describió la intención como "cumplimiento total con todo el lenguaje de shell C (excepto control de trabajos )" pero con mejoras en el diseño del lenguaje y adaptación a las diferencias entre Unix y un PC. La mejora más importante fue un analizador de arriba hacia abajo que permitía anidar o canalizar estructuras de control , algo que el shell C original no podía admitir, dado su analizador ad hoc. Hamilton también agregó nuevas características de lenguaje que incluyen procedimientos integrados y definidos por el usuario, variables locales estructuradas en bloques y aritmética de punto flotante. La adaptación a una PC incluyó soporte para el nombre de archivo y otras convenciones en una PC y el uso de subprocesos en lugar de bifurcaciones (que no estaban disponibles ni en OS/2 ni en Windows) para lograr paralelismo , por ejemplo, en la configuración de una canalización.