
El intérprete de comandos C ( csh o su versión mejorada, tcsh ) es un intérprete de comandos de Unix creado por Bill Joy mientras era estudiante de posgrado en la Universidad de California, Berkeley, a finales de la década de 1970. Ha tenido una amplia distribución, comenzando con la versión 2BSD de la Berkeley Software Distribution (BSD), que Joy distribuyó por primera vez en 1978. [ 1 ] [ 2 ] Otros colaboradores iniciales en las ideas o el código fueron Michael Ubell, Eric Allman , Mike O'Brien y Jim Kulp. [ 3 ]
El intérprete de comandos C es un procesador de comandos que normalmente se ejecuta en una ventana de texto, permitiendo al usuario escribir y ejecutar comandos. También puede leer comandos desde un archivo, llamado script . Al igual que todos los intérpretes de comandos de Unix, admite comodines en los nombres de archivo , tuberías , documentos aquí , sustitución de comandos , variables y estructuras de control para la comprobación de condiciones e iteración . Lo que diferenció al intérprete de comandos C de otros, especialmente en la década de 1980, fueron sus características interactivas y su estilo general. Sus nuevas características lo hicieron más fácil y rápido de usar. 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 simbólico al otro, de modo que ambos nombres se refieren a la misma versión mejorada del intérprete de comandos C. El código fuente original de csh, en src/bin/csh/, y el binario forman parte de NetBSD y OpenBSD .
En Debian y algunos derivados (incluido Ubuntu ), existen dos paquetes diferentes: csh y tcsh. El primero se basa en la versión original de csh de BSD [ 4 ] [ 5 ] y el segundo es la versión mejorada de tcsh. [ 6 ] [ 7 ]
tcsh añadió autocompletado de nombres de archivo y comandos, así como conceptos de edición de línea de comandos tomados del sistema Tenex , que es la fuente de la "t". [ 8 ] Debido a que solo añadió funcionalidad y no cambió lo que ya existía, tcsh se mantuvo compatible con versiones anteriores [ 9 ] con el shell C original. Aunque comenzó como una rama secundaria del árbol de código 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. [ 10 ]
Objetivos y características del diseño
Los principales objetivos de diseño para el intérprete de comandos C eran que se pareciera más al lenguaje de programación C y que fuera más adecuado para el uso interactivo.
Más bien C
El sistema Unix se había escrito casi exclusivamente en C, por lo que el primer objetivo del intérprete de comandos C fue crear un lenguaje de comandos con un estilo más coherente con el resto del sistema. Las palabras clave, el uso de paréntesis, la gramática de expresiones integrada del intérprete de comandos C y la compatibilidad con matrices recibieron una fuerte influencia de C.
Según los estándares actuales, la shell C puede no parecer particularmente más parecida a C que muchos otros lenguajes de scripting populares. Pero durante las décadas de 1980 y 1990, la diferencia se consideraba notable, especialmente en comparación con la shell Bourne (también conocida como sh ), la shell dominante de la época, escrita por Stephen Bourne en Bell Labs . Este ejemplo ilustra los operadores de expresión y la sintaxis más convencionales de la shell C.
#!/bin/sh if [ $days -gt 365 ] then echo Esto es más de un año. fiC shell
#!/bin/csh if ( $days > 365 ) then echo Esto es más de un año. endifEl Bourne sh carecía de una gramática de expresiones . La condición entre corchetes debía evaluarse mediante el método más lento de ejecutar el programa de pruebaif externo. El comando de sh tomaba sus argumentos como un nuevo comando para ejecutarse como un proceso hijo . Si el hijo finalizaba con un código de retorno cero , sh buscaba una thencláusula (una instrucción separada, pero a menudo escrita unida en la misma línea con un punto y coma) y ejecutaba ese bloque anidado. De lo contrario, ejecutaba el else. El enlace duro al programa de prueba como " test" y " [" proporcionaba la ventaja notacional de los corchetes y la apariencia de que la funcionalidad de 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 era un estilo tomado de ALGOL 68. [ 11 ]
En cambio, csh podía evaluar la expresión directamente, lo que la hacía más rápida. Además, afirmaba ofrecer 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 al de C.
Aquí tenemos un segundo ejemplo, que compara scripts que calculan las primeras 10 potencias de 2.
#!/bin/sh i = 2 j = 1 while [ $j -le 10 ] do echo '2 **' $j = $i i = ` expr $i '*' 2 ` j = ` expr $j + 1 ` done #!/bin/csh establecer i = 2 establecer j = 1 mientras ( $j < = 10 ) echo '2 **' $j = $i @ i * = 2 @ j++ finNuevamente, debido a la falta de una gramática de expresiones, el script sh utiliza la sustitución de comandos y el comando expr . ( El shell POSIX moderno sí tiene dicha gramática: la instrucción podría escribirse i=$((i * 2))o : "$((i *= 2))".)
Por último, aquí hay un tercer ejemplo que muestra los diferentes estilos para una instrucción switch .
#!/bin/sh for i in d* do case $i in d? ) echo $i es corto ;; * ) echo $i es largo ;; esac done#!/bin/csh foreach i ( d* ) switch ( $i ) case d?: echo $i es corto breaksw default : echo $i es largo endsw endEn el shscript, " ;;" marca el final de cada caso porque sh no permite declaraciones nulas de otra manera.
Mejoras para el uso interactivo
El segundo objetivo era mejorar la interacción con el intérprete de comandos C. Se introdujeron numerosas funciones nuevas que facilitaron, agilizaron y simplificaron su uso mediante la escritura de comandos en la terminal. Los usuarios podían realizar tareas con muchas menos pulsaciones de teclas y el sistema funcionaba con mayor rapidez. Las funciones más importantes fueron el historial y los mecanismos de edición, los alias, las pilas de directorios, la notación de tilde, cdpath, el control de trabajos y el hash de rutas. Estas nuevas funciones resultaron muy populares y muchas de ellas han sido posteriormente copiadas por otros intérpretes de comandos de Unix.
Historia
El historial permite a los usuarios recuperar comandos anteriores y volver a ejecutarlos con solo pulsar unas pocas teclas. Por ejemplo, al escribir dos signos de exclamación (" !!") [ 12 ] como comando, se ejecuta el comando inmediatamente anterior. Otras combinaciones cortas de teclas, como " !$" (que significa "el último argumento del comando anterior"), permiten pegar fragmentos de comandos anteriores y editarlos para formar un nuevo comando.
Operadores de edición
La edición puede realizarse no solo en el texto de un comando anterior, sino también en la sustitución de variables. Los operadores abarcan desde la simple búsqueda y reemplazo de cadenas hasta el análisis de una ruta de archivo para extraer un segmento específico.
Alias
Los alias permiten al usuario escribir el nombre de un alias y que el intérprete de comandos C lo expanda internamente al conjunto de palabras que el usuario haya definido. En muchas situaciones sencillas, los alias son más rápidos y prácticos que los scripts.
Pila de directorios
La pila de directorios permite al usuario insertar o extraer elementos del directorio de trabajo actual , lo que facilita el desplazamiento entre diferentes ubicaciones del sistema de archivos.
Notación de tilde
La notación de tilde ofrece una forma abreviada de especificar rutas de acceso relativas al directorio principal utilizando el ~carácter " ".
Finalización del nombre de archivo
La tecla Escape se puede usar de forma interactiva para mostrar posibles sugerencias para completar un nombre de archivo al final de la línea de comandos actual.
Ruta de CD
Cdpath extiende la noción de ruta de búsqueda al cdcomando (cambiar directorio): si el directorio especificado no está en el directorio actual , csh intentará encontrarlo en los directorios de cdpath.
Control de trabajo
Hasta bien entrada la década de 1980, la mayoría de los usuarios solo disponían de terminales simples en modo de caracteres que impedían el uso de múltiples ventanas, por lo que solo podían trabajar en una tarea a la vez. El control de trabajos del intérprete de comandos C permitía al usuario suspender la actividad actual y crear una nueva instancia del intérprete de comandos C, denominada trabajo, escribiendo ^Z. El usuario podía entonces alternar entre trabajos utilizando el fgcomando . Se decía que el trabajo activo estaba en primer plano. Se decía que los demás trabajos estaban suspendidos (detenidos) o ejecutándose en segundo plano .
Hashing de ruta
El hash de rutas acelera la búsqueda de archivos ejecutables por parte del intérprete de comandos C. En lugar de realizar una llamada al sistema de archivos en cada directorio de ruta, uno por uno, hasta encontrar el archivo o agotar las posibilidades, el intérprete de comandos C consulta una tabla hash interna creada mediante el escaneo de los directorios de ruta. Esta tabla suele indicar al intérprete de comandos C dónde encontrar el archivo (si existe) sin necesidad de buscarlo y se puede actualizar con el rehashcomando correspondiente.
Descripción general del idioma
El intérprete de comandos C opera línea por línea. Cada línea se divide en un conjunto de palabras separadas por espacios u otros caracteres con significado especial, como paréntesis, operadores de redirección de entrada/salida y tuberías, puntos y comas y signos de ampersand.
Declaraciones básicas
Una instrucción básica simplemente ejecuta un comando. La primera palabra se toma como el 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 al comando.
A nivel de enunciado básico, estas son algunas de las características de la gramática:
Comodín
El intérprete de comandos C, al igual que todos los intérpretes de comandos 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 archivo que coinciden (ver 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, usando el guion.[^...]coincide con cualquier personaje que no esté en el conjunto.
El intérprete de comandos C también introdujo varias conveniencias de notación (a veces conocidas como comodines extendidos ), que posteriormente fueron copiadas por otros intérpretes de comandos de Unix.
abc{def,ghi}es alternancia (también conocida como expansión de llaves ) y se expande a abcdef abcghi .~significa el directorio principal del usuario actual.~usersignifica el directorio principal del usuario .
Se admiten varios comodines a nivel de directorio, por ejemplo, " */*.c".
Desde la versión 6.17.01, también se admite el uso recursivo de comodines en zsh (por ejemplo, " **/*.c" o " ") con la opción.***/*.htmlglobstar
En Unix, la decisión de que el intérprete de comandos interpretara los comodines fue crucial. Esto significaba que los comodines funcionarían con cualquier comando, siempre del mismo modo. Sin embargo, esta decisión se basaba en la capacidad de Unix para pasar listas de argumentos largas de manera eficiente mediante la llamada al sistema `exec` , que `csh` utiliza para ejecutar comandos. En cambio, en Windows , la interpretación de comodines la realiza cada aplicación. Esto es una herencia de MS-DOS, que solo permitía pasar una línea de comandos de 128 bytes a una aplicación, lo que hacía que el uso de comodines en el símbolo del sistema de DOS fuera poco práctico. Si bien las versiones modernas de Windows pueden pasar líneas de comandos de hasta aproximadamente 32 000 caracteres Unicode , la responsabilidad de la interpretación de comodines recae en la aplicación.
redirección de E/S
Por defecto, cuando csh ejecuta un comando, este hereda los descriptores de archivo stdio de csh para stdin , stdout y stderr , que normalmente apuntan a la ventana de la consola donde se ejecuta el intérprete de comandos C. Los operadores de redirección de E/S permiten que el comando utilice un archivo para la entrada o salida.
> fileEsto significa que la salida estándar se escribirá en un archivo , sobrescribiéndolo si existe y creándolo si no. Los errores seguirán apareciendo en la ventana del intérprete de comandos.>& filesignifica que tanto stdout como stderr se escribirán en el archivo , sobrescribiéndolo si existe y creándolo si no existe.>> filesignifica que la salida estándar se agregará al final del archivo .>>& filesignifica que tanto stdout como stderr se agregarán al final del archivo .< filesignifica que la entrada estándar se leerá desde el archivo .<< stringes 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 subproceso.
set filter = "$home" '/filter' mkfifo "$filter" cat "$filter" & ( ( ls /root/ || echo Sin acceso. ) > "$filter" ) >& /dev/null Los sistemas que admiten descriptores de archivo como archivos pueden utilizar la siguiente solución alternativa.
( ( ( echo ok ; '' ) > /dev/fd/0 ) >& /dev/null < /dev/fd/1 ) | ( echo "$<" adiós )Unión
Los comandos pueden unirse 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.
Tubería
Los comandos se pueden conectar mediante una tubería, lo que hace que la salida de un comando se introduzca en la entrada del siguiente. Ambos comandos se ejecutan simultáneamente .
|significa conectar la salida estándar a la entrada estándar del siguiente comando. Los errores aún aparecen en la ventana del intérprete de comandos.|&significa conectar tanto stdout como stderr a stdin del siguiente comando.
Ejecutar simultáneamente significa "en paralelo". En un sistema multinúcleo (con varios procesadores), los comandos canalizados pueden ejecutarse literalmente al mismo tiempo; de lo contrario, el planificador del sistema operativo divide el tiempo de ejecución entre ellos.
Dado un comando, por ejemplo, " a | b", el intérprete de comandos crea una tubería , luego inicia tanto acomo bcon stdio para los dos comandos redirigidos de modo que aescribe su stdout en la entrada de la tubería mientras blee stdin de la salida de la tubería. Las tuberías son implementadas por el sistema operativo con una cierta cantidad de búfer para que apueda escribir durante un tiempo antes de que la tubería se llene, pero una vez que la tubería se llena, cualquier nueva escritura bloqueará dentro del sistema operativo hasta que blea lo suficiente para desbloquear nuevas escrituras. Si bintenta leer más datos de los que están disponibles, se bloqueará hasta que ahaya escrito más datos o hasta que la tubería se cierre, por ejemplo, si asale.
Sustitución de variables
Si una palabra contiene un signo de dólar, " $", los caracteres siguientes 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 a la referencia, permiten editar la ruta de acceso (por ejemplo, " :e" para extraer solo la extensión) y otras operaciones.
Citar y escapar
Los mecanismos de comillas permiten que caracteres especiales, como espacios en blanco, comodines, paréntesis y signos de dólar, se interpreten 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 entre paréntesis se interpretan como literales, pero las sustituciones de variables y comandos se siguen realizando.'La cadena'es una cita textual. Toda la cadena entrecomillada se interpreta literalmente.
Las comillas dobles dentro de comillas dobles deben escaparse con "\"". Lo mismo se aplica al símbolo del dólar, para evitar la expansión de variables "\$". Para las comillas invertidas, para evitar el anidamiento de sustitución de comandos, se requieren comillas simples "'\`'".
Sustitución de comandos
La sustitución de comandos permite que la salida de un comando se utilice como argumento de otro.
`El comando`significa tomar la salida del comando , analizarla en palabras y pegarlas de nuevo en la línea de comandos.
El siguiente es un ejemplo de sustituciones de comandos anidados con el síndrome del palillo inclinado :
echo "`echo " \"\` "echo " \"\\\"\\\`\" "echo " \"\\\"\\\\\\\"\\\\\\\`\\\"\" "echo " \"\\\"\\\\\\\"\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\`\\\\\\\"\\\"\" "eco " \"\\\"\\\\\\\"\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\`\\\\\\\\\\\\\\\"\\\\\\\"\\\"\" "pwd" \"\\\"\\\\\\\"\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\`\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\`\\\\\\\\\\\\\\\"\\\\\\\\"\\\\\\\`\\\\\\\"\\\"\\\"\\\`\\\"\"\"` \"Ejecución en segundo plano
Normalmente, cuando el intérprete de comandos C inicia un comando, espera a que este finalice antes de mostrarle al usuario otro indicador que le indique que puede escribir un nuevo comando.
- El comando
&significa iniciar un comando en segundo plano y solicitar inmediatamente un nuevo comando.
Subcapas
Un subproceso es una copia hija separada del proceso principal que hereda el estado actual, pero que luego puede realizar cambios, por ejemplo, en el directorio actual, sin afectar al proceso principal.
(comandos)significa ejecutar comandos en un subproceso.
Estructuras de control
El intérprete de comandos C proporciona estructuras de control tanto para la comprobación de condiciones como para la iteración . Las estructuras de control para la comprobación de condiciones son las sentencias if y switch. Las estructuras de control para la iteración son las sentencias while, foreach y repeat.
si la instrucción
Existen dos formas de la instrucción if . La forma corta se escribe en una sola línea, pero solo puede especificar un único comando si la expresión es verdadera.
si ( expresión ) comando La forma extendida utiliza las palabras clave then, else y endif para permitir que se aniden bloques de comandos dentro de la condición.
si ( expresión1 ) entonces comandos sino si ( expresión2 ) entonces comandos ... si no , comandos fin siSi las palabras clave else e if aparecen en la misma línea, csh las encadena en lugar de anidarlas; el bloque termina con un único endif.
instrucción switch
La instrucción switch compara una cadena con una lista de patrones, que puede contener caracteres comodín. Si no encuentra ninguna coincidencia, se ejecuta la acción predeterminada, si la hay.
interruptor ( cadena ) caso patrón1: comandos breaksw patrón de caso2 : comandos descansos ... por defecto : comandos rupturasw terminawmientras que la declaración
La instrucción while evalúa una expresión. Si es verdadera, el intérprete de comandos ejecuta los comandos anidados y luego repite el proceso mientras la expresión siga siendo verdadera.
mientras ( expresión ) comandos fininstrucción para cada
La instrucción foreach toma una lista de valores, generalmente una lista de nombres de archivo generados mediante caracteres comodín, y luego, para cada valor, asigna ese valor a la variable del bucle y ejecuta los comandos anidados.
para cada variable de bucle ( lista de valores ) comandos finrepetir declaración
La instrucción repeat repite un único comando un número entero de veces.
repetir comando entero Variables
El intérprete de comandos C implementa variables de entorno y de shell . [ 13 ] Las variables de entorno, creadas mediante la setenvinstrucción, son siempre cadenas simples, que se pasan a cualquier proceso hijo , que recupera estas variables a través del envp[]argumento de main().
Las variables de shell, creadas mediante las sentencias set`or` @, son internas al intérprete de comandos C. No se pasan a los procesos hijos. Las variables de shell pueden ser cadenas simples o matrices de cadenas. Algunas variables de shell están predefinidas y se utilizan para controlar diversas opciones internas del intérprete de comandos C, por ejemplo, qué sucede si un comodín no coincide con nada.
En las versiones actuales de csh, las cadenas pueden tener una longitud arbitraria, llegando incluso a contener millones de caracteres.
Las variables se pueden ampliar según sea necesario. Sin embargo, si se desea trabajar con un tamaño fijo, se prefiere la siguiente sintaxis.
# Crea una variable lo suficientemente grande como para contener 1024 elementos. set fixed = { , }{ , }{ , } { , }{ , }{ , }{ , }{ , } { , }Expresiones
El intérprete de comandos C implementa una gramática de expresiones enteras de 32 bits con operadores tomados de C, pero con algunos operadores adicionales para comparaciones de cadenas y pruebas del sistema de archivos, por ejemplo, para comprobar la existencia de un archivo. Los operadores deben estar separados por espacios en blanco de sus operandos. Las variables se referencian 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é va 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 intérprete de comandos de C, es de derecha a izquierda. Por ejemplo,
// C agrupa 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 # imprime 0En el ejemplo de la shell C, los paréntesis sirven para evitar confundir los operadores de desplazamiento de bits con los operadores de redirección de E/S. En ambos lenguajes, los paréntesis siempre se pueden usar para especificar explícitamente el orden de evaluación deseado, aunque solo sea por claridad.
Los valores de retorno están limitados a 8 bits. Para exitexpresiones, se puede utilizar el operador de negación unaria para la evaluación de 32 bits.
¡ Salida ! ! 256 # Devuelve 1.Recepción
Aunque el propio Stephen Bourne reconoció que csh era superior a su shell para uso interactivo, [ 14 ] nunca ha sido tan popular para la creación de scripts.
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 . [ 15 ]
Inicialmente, y durante la década de 1980, no se podía garantizar la presencia de csh en todos los sistemas Unix y similares, pero sí la de sh, lo que lo convertía en una mejor opción para cualquier script que debiera ejecutarse en otras máquinas. A mediados de la década de 1990, csh estaba ampliamente disponible, pero su uso para scripts recibió nuevas críticas por parte del comité POSIX , [ 16 ] que especificó que solo debería haber un intérprete de comandos preferido, KornShell , tanto para fines interactivos como de scripting. El intérprete de comandos C también recibió críticas de otros [ 17 ] [ 18 ] por supuestos defectos de sintaxis, características faltantes y mala implementación.
- Defectos de sintaxis: eran inconsistencias generalmente simples pero innecesarias en la definición del lenguaje. Por ejemplo, los comandos
set,setenvyaliashací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 de igual parasetpero no parasetenvoalias; se requerían paréntesis alrededor de una lista de palabras parasetpero no parasetenvoalias, etc. De manera similar, las construcciones de bucleif,switchy usan palabras clave innecesariamente diferentes (endif,endswyend) para terminar los bloques anidados. - Funcionalidades faltantes: las más citadas son la falta de capacidad para manipular los descriptores de archivo de stdio de forma independiente y la falta de compatibilidad con funciones. Aunque carece de compatibilidad con funciones, los alias sirven como solución alternativa. Para varias líneas de código, los alias deben estar entre comillas simples, y cada final de línea debe ir precedido de una barra invertida (el final de la última línea debe ir precedido de una comilla simple para delimitar el final del alias). La recursión es preferible a los alias en los scripts como solución alternativa para las funciones (se proporciona un ejemplo a continuación).
- La implementación, que utilizó un analizador ad hoc , ha recibido las críticas más severas. A principios de la década de 1970, la tecnología de compiladores estaba suficientemente madura [ 19 ] como para que la mayoría de las nuevas implementaciones de lenguajes utilizaran un analizador descendente o ascendente capaz de reconocer una gramática completamente recursiva . Se desconoce por qué se optó por un diseño ad hoc para el intérprete de comandos C. Puede deberse simplemente a que, como Joy expresó en una entrevista en 2009, «Cuando comencé a trabajar en Unix, no era un programador muy bueno». [ 20 ] El diseño ad hoc implicaba que el lenguaje C no era completamente recursivo. Existía un límite en la complejidad de los comandos que podía manejar.
Funcionaba 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, podía fallar fácilmente, produciendo solo un mensaje de error críptico o un resultado no deseado. Por ejemplo, el intérprete de comandos C no admitía la redirección de salida entre estructuras de control. Intentar redirigir la salida de un foreachcomando grepsimplemente no funcionaba. (La solución alternativa, que funciona para muchas de las quejas relacionadas con el analizador, consiste en dividir el código en scripts separados. Si foreachse mueve a un script separado, la redirección funciona porque los scripts se ejecutan mediante la creación de una nueva copia de csh que hereda los identificadores stdio correctos. También es posible dividir el código en un solo archivo. A continuación se muestra un ejemplo de cómo dividir el código en un solo archivo).
Otro ejemplo es el comportamiento anómalo que se observa en los siguientes fragmentos. Ambos parecen significar: "Si 'myfile' no existe, créalo escribiendo 'mytext' en él". Sin embargo, la versión de la derecha siempre crea un archivo vacío porque el orden de evaluación del intérprete de comandos C consiste en buscar y evaluar los operadores de redirección de E/S en cada línea de comandos a medida que la lee, antes de examinar el resto de la línea para comprobar si contiene una estructura de control.
# Funciona como se esperaba si ( ! -e myfile ) entonces echo mytext > myfile fin si # Siempre crea un archivo vacío if ( ! -e myfile ) echo mytext > myfile # Solución alternativa (solo 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 ya existe. La implementación también es criticada por sus mensajes de error notoriamente deficientes, por ejemplo, "0: Evento no encontrado", que no proporciona información útil sobre el problema.
Sin embargo, mediante la práctica, es posible superar esas deficiencias (lo que permite al programador adoptar enfoques mejores y más seguros al implementar un script).
El error "0: Evento no encontrado" indica que no hay comandos guardados en el historial. Es posible que el historial no funcione correctamente en los scripts, pero tener un conjunto predefinido 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 'Introduzca un número para ejecutar un comando del historial: ' set cmdexec = "$<" ( exit ( ! ( "$cmdexec" > 0 && \ "$cmdexec" < = "$#cmdlist" ) ) ) >& /dev/null if ( "$status" ) then echo 'Número de evento no válido.' foreach cmd ( $cmdlist :q ) echo "$cmd" end exit -1 endif eval "$cmdlist[$cmdexec]"Prefiero romper el código recursivamente en el 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.' exit -1 endif alias function 'set argv = ( \!* ) ; source "$main"' set main = "$0" set ret = "`function myfunc`" echo "$ret" exit endifir a "$1" ; cambio mifunción: función myfunc2 echo "Una función." salir mifunc2: echo "Otra función." salirInfluencia

El intérprete de comandos C tuvo un éxito rotundo al introducir numerosas innovaciones, como el mecanismo de historial , los alias , la notación con tilde , el autocompletado interactivo de nombres de archivo, una gramática de expresiones integrada y otras más, que posteriormente fueron copiadas por otros intérpretes de comandos de Unix. Sin embargo, a diferencia de sh , que ha generado una gran cantidad de clones desarrollados de forma independiente, como ksh y bash , solo se conocen dos clones de csh. (Dado que tcsh se basó en el código de 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 , [ 21 ] un libro que describía un programa que había escrito llamado "SH", pero que en realidad copiaba el diseño del lenguaje y las características de csh, no de sh. Los disquetes complementarios que contenían el código fuente completo de SH y de un conjunto básico de utilidades tipo Unix (cat, cp, grep, etc.) estaban disponibles por 25 y 30 dólares, respectivamente, del editor. Las estructuras de control, la gramática de expresiones, el mecanismo de historial y otras características del SH de Holub eran idénticas a las del intérprete de comandos C.
En 1988, Hamilton Laboratories comenzó a distribuir Hamilton C shell para OS/2 . [ 22 ] Incluía tanto un clon de csh como un conjunto de utilidades tipo Unix. En 1992, Hamilton C shell se lanzó para Windows NT . [ 23 ] La versión de Windows continúa recibiendo soporte activo, pero la versión de OS/2 se descontinuó en 2003. [ 23 ] Una referencia rápida de principios de 1990 [ 24 ] describía la intención como "cumplimiento total con todo el lenguaje C shell (excepto el control de trabajos )", pero con mejoras en el diseño del lenguaje y adaptación a las diferencias entre Unix y una PC. La mejora más importante fue un analizador sintáctico descendente que permitía anidar o canalizar estructuras de control , algo que el C shell original no podía soportar, dado su analizador sintáctico ad hoc. Hamilton también agregó nuevas características de lenguaje, incluyendo procedimientos integrados y definidos por el usuario, variables locales estructuradas en bloques y aritmética de punto flotante. La adaptación a un PC incluyó la compatibilidad con el nombre de archivo y otras convenciones propias de un PC, así como el uso de subprocesos en lugar de bifurcaciones (que no estaban disponibles ni en OS/2 ni en Windows) para lograr el paralelismo , por ejemplo, al configurar una tubería.
En 2026, Tropibyte lanzó C Shell para Windows (cshw), una implementación nativa de csh para Win32 distribuida sin dependencias de Cygwin ni WSL. Al igual que Hamilton C shell, evita el paralelismo basado en fork, utilizando corrutinas y primitivas de sincronización de Windows en su lugar. [ 25 ]
Véase también
Referencias
- ↑ Harley Hahn, Guía de Harley Hahn para Unix y Linux Archivado el 24 de agosto de 2019 en Wayback Machine .
- ↑ Notas del Laboratorio de Ingeniería de Berkeley, Volumen 1, Número 2, octubre de 2001. Archivado el 9 de julio de 2010 en Wayback Machine .
- ↑ Una introducción al shell C Archivado el 13 de julio de 2018 en Wayback Machine por Bill Joy .
- ↑ Ubuntu - Detalles del paquete csh . launchpad.net.
- ↑ Debian - Detalles del paquete csh . tracker.debian.org.
- ↑ Ubuntu - Detalles del paquete tcsh . launchpad.net.
- ↑ Debian - Detalles del paquete tcsh . tracker.debian.org.
- ↑ Ken Greer (3 de octubre de 1983). "C shell con reconocimiento/autocompletado de comandos y nombres de archivo" . Grupo de noticias : net.sources . Consultado el 29 de diciembre de 2010 .
- ↑ Página man de tcsh(1) . tcsh.
- ↑ Corrige el archivo en tcsh-17 de junio de 2000.
- ↑ Re: Late Bloomers Revisited Publicación de USENET en comp.lang.misc por Piercarlo "Peter" Grandi, Departamento de Ciencias de la Computación, UCW Aberystwyth, Reino Unido, 17 de diciembre de 1989.
- ↑ Se pronuncia "bang, bang"
- ↑ Troy, Douglas (1990). Sistemas UNIX . Fundamentos de la informática. Benjamin/Cumming Publishing Company. pág. 25.
- ↑ Bourne, Stephen R. (octubre de 1983). "The Unix Shell" . BYTE . pág. 187. Consultado el 28 de junio de 2026 .
- ↑ La guía del iniciado para el universo (PDF) . Charles River Data Systems, Inc. 1983. pág. 13.
- ↑ Norma IEEE para Tecnología de la Información, Interfaz de Sistema Operativo Portátil (POSIX), Parte 2: Shell y Utilidades, Volumen 2. IEEE Std 1003.2-1992, págs. 766-767. ISBN 1-55937-255-9.
- ↑ Tom Christiansen considera que la programación en Csh es perjudicial.
- ↑ Diez razones principales para no usar la shell C por Bruce Barnett
- ↑ David Gries (1971). Construcción de compiladores para computadoras digitales. John Wiley & Sons. ISBN 0-471-32776-X.
- ^ Bill Joy en conversación con Brent Schlender, Churchill Club, Santa Clara, CA, 11 de febrero de 2009 .
- ↑ Holub, Allen (1986–1987). On Command: Writing a Unix-Like Shell for MS-DOS (Segunda edición). M&T Books, Redwood City, CA. ISBN 0-934375-29-1.
- ↑ Hamilton, Douglas. "Anuncio de Hamilton C shell" (PDF) . IBM Personal Systems Developer (verano de 1989): 119–121 . Consultado el 11 de julio de 2020 .
- 1 2 Hamilton, Nicole (5 de marzo de 2017). "Notas de la versión 5.2.g de Hamilton C shell para Windows" . Hamilton Laboratories, Redmond, WA . Recuperado el 3 de abril de 2018 .
- ↑ Referencia rápida de la capa C de Hamilton (PDF) . Hamilton Laboratories, Wayland, MA. 1988–1990 . Consultado el 11 de julio de 2020 .
- ↑ "C Shell para Windows" . Tropibyte, Inc. Mayo de 2026. Consultado el 20 de mayo de 2026 .
Lecturas adicionales
- Anderson, Gail; Paul Anderson (1986). The UNIX C Shell Field Guide . Prentice-Hall. ISBN 0-13-937468-X.
- Wang, Paul (1988). Introducción a Berkeley UNIX . Wadsworth Pub. Co. ISBN 0-534-08862-7.
- DuBois, Paul (1995). Uso de csh y tcsh . O'Reilly & Associates. ISBN 1-56592-132-1.
- Arick, Martin R. (1993). UNIX C Shell Desk Reference . John Wiley & Sons. ISBN 0-471-55680-7.
- "Introducción a la programación en C Shell" . Departamento de Ciencias de la Computación de Canisius College. Archivado del original el 19 de agosto de 2011. Consultado el 23 de junio de 2010 .
Enlaces externos
- Introducción al intérprete de comandos C, por William Joy .
- Linux en pocas palabras: Capítulo 8. csh y tcsh .
- Código fuente histórico de csh de 2BSD con fecha del 2 de febrero de 1980.
- El Árbol Unix , distribuciones históricas completas de Unix.
- La programación en Csh se considera dañina .
- Diez razones principales para no usar el intérprete de comandos C.
- shells de Unix
- Software de 1978
- Software libre multiplataforma
- Software que utiliza la licencia BSD.