C-shell (concha C)

Concha de Unix

C-shell (concha C)
Autor(es) original(es)Bill Joy
Lanzamiento inicial1978 ; hace 46 años ( 1978 )
Versión estable
6.20.00 / 24 de noviembre de 2016 ; hace 7 años [1] ( 24 de noviembre de 2016 )
Repositorio
  • github.com/freebsd/freebsd-src/tree/main/bin/csh
Escrito endo
Sistema operativoBSD , UNIX , UNOS , Linux , macOS
TipoConcha de Unix
LicenciaLicencia BSD
C Shell ejecutándose en Servicios de Windows para UNIX

El C shell ( csh o la versión mejorada, tcsh ) es un shell de Unix creado por Bill Joy mientras era estudiante de posgrado en la Universidad de California, Berkeley a fines de la década de 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 C shell es un procesador de comandos que normalmente se ejecuta en una ventana de texto, lo que permite al usuario escribir y ejecutar comandos. El C shell también puede leer comandos de un archivo, llamado script . Como todos los shells de Unix, admite comodines en los nombres de archivo , canalización , documentos aquí , sustitución de comandos , variables y estructuras de control para pruebas de condición e iteración . Lo que diferenciaba al C shell de otros, especialmente en la década de 1980, eran 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 un enlace simbólico al otro, de modo que cualquiera de los dos nombres hace referencia a la misma versión mejorada del shell C. El código fuente y el binario originales de csh son parte de NetBSD .

En Debian y algunos derivados (incluido Ubuntu ), existen dos paquetes diferentes: csh y tcsh. El primero se basa en la versión BSD original de csh [5] [6] y el segundo es la versión mejorada de tcsh. [7] [8]

tcsh agregó nombres de archivo, finalización de comandos y conceptos de edición de línea de comandos 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 C shell original. Aunque comenzó como una rama lateral del árbol de código fuente original que había creado Joy, tcsh es ahora la rama principal para el desarrollo continuo. tcsh es muy estable, pero continúan apareciendo nuevas versiones aproximadamente una vez al año, que consisten principalmente en correcciones de errores menores. [11]

Objetivos y características del diseño

Los principales objetivos de diseño para el C shell eran que se pareciera más al lenguaje de programación C y que fuera mejor para el uso interactivo.

Más bien C

El sistema Unix había sido escrito casi exclusivamente en C, por lo que el primer objetivo del shell C era crear un lenguaje de comandos que fuera más coherente estilísticamente con el resto del sistema. Las palabras clave, el uso de paréntesis, la gramática de expresiones integrada del shell C y el soporte para matrices estaban fuertemente influenciados por C.

Según los estándares actuales, C shell puede no parecer mucho más parecido a C que muchos otros lenguajes de programación populares. Pero durante los años 80 y 90, la diferencia se veía como sorprendente, en particular cuando se comparaba con Bourne shell (también conocido como sh ), el shell dominante en ese momento escrito por Stephen Bourne en Bell Labs . Este ejemplo ilustra los operadores de expresión y la sintaxis más convencionales de C shell .

Concha Bourne

#!/bin/sh if [ $days -gt 365 ] then echo Esto es más de un año. fi           

C-shell (concha C)

#!/bin/csh if  (  $days > 365 )  then echo Esto es más de un año. endif 

El sh de Bourne carecía de una gramática de expresión . La condición entre corchetes debía evaluarse mediante el medio más lento de ejecutar el programa de prueba externo . El comando de sh iftomaba sus palabras de argumento como un nuevo comando que se ejecutaba como un proceso secundario . Si el proceso secundario salía con un código de retorno cero , sh buscaría una thenclá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. La vinculación rígida del programa de prueba como " test" y " [" dio la ventaja de notación de los corchetes y la apariencia de que la funcionalidad de test era parte del lenguaje sh. El uso de sh de una palabra clave invertida para marcar el final de un bloque de control era un estilo tomado de ALGOL 68. [ 12]

En cambio, csh podía evaluar la expresión directamente, lo que la hacía más rápida. También afirmaba que era más legible: sus expresiones usaban 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 era más parecido al de C.

A continuación se muestra un segundo ejemplo, comparando scripts que calculan las primeras 10 potencias de 2.

Concha Bourne

#!/bin/sh i = 2 j = 1 mientras [ $j -le 10 ] hacer echo '2 **' $j = $i i = ` expr $i '*' 2 ` j = ` expr $j + 1 ` hecho                    

C-shell (concha C)

#!/bin/csh establecer i  = 2 establecer j  = 1 mientras  (  $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 utiliza la sustitución de comandos y el comando expr . ( El shell POSIX moderno tiene una gramática de este tipo: 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 switch .

Concha Bourne

#!/bin/sh para  i en d* hacer caso $i en d? ) echo $i es corto ;; * ) echo $i es largo ;; esac hecho                  

C-shell (concha C)

#!/bin/csh foreach i ( d* )  switch  (  $i  )  case d?: echo  $i es corto breaksw  predeterminado : echo  $i es largo endsw fin

En el script sh, " ;;" marca el final de cada caso porque en caso contrario sh no permite declaraciones nulas.

Mejoras para el uso interactivo

El segundo objetivo era mejorar el uso interactivo del C shell. Introdujo numerosas características nuevas que lo hicieron más fácil, rápido y amigable de usar al escribir comandos en una terminal. Los usuarios podían hacer cosas con muchas menos pulsaciones de teclas y funcionaba más rápido. Las más significativas de estas nuevas características eran los mecanismos de historial y 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 características resultaron muy populares y muchas de ellas han sido copiadas desde entonces por otros shells de Unix.

Historia

El historial permite a los usuarios recordar comandos anteriores y volver a ejecutarlos con solo pulsar unas pocas teclas. Por ejemplo, si se pulsan dos signos de exclamación (" !!") [13] como comando, se ejecuta el comando inmediatamente anterior. Otras combinaciones de teclas cortas, por ejemplo, " !$" (que significa "el argumento final del comando anterior"), permiten pegar fragmentos de comandos anteriores y editarlos para formar un nuevo comando.

Operadores de edición

La edición se puede realizar no solo en el texto de un comando anterior, sino también en sustituciones de variables. Los operadores varían desde la simple búsqueda y reemplazo de cadenas hasta el análisis de una ruta para extraer un segmento específico.

Alias

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. En muchas situaciones simples, los alias se ejecutan más rápido y son más convenientes que los scripts.

Pila de directorios

La pila de directorios permite al usuario insertar o extraer el directorio de trabajo actual , lo que hace más fácil saltar de un lugar a otro del sistema de archivos.

Notación de tilde

La notación tilde ofrece una forma abreviada de especificar rutas relativas al directorio de inicio utilizando el ~carácter " ".

Completar nombre de archivo

La tecla Escape se puede utilizar de forma interactiva para mostrar posibles finalizaciones de un nombre de archivo al final de la línea de comando actual.

Ruta de acceso

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 cdpath.

Control de trabajo

Hasta bien entrada la década de 1980, la mayoría de los usuarios sólo tenían terminales simples en modo carácter que impedían la presencia de varias ventanas, por lo que sólo podían trabajar en una tarea a la vez. El control de tareas del shell C permitía al usuario suspender la actividad actual y crear una nueva instancia del shell C, llamada tarea, escribiendo ^Z. El usuario podía entonces alternar entre tareas utilizando el fgcomando . Se decía que la tarea activa estaba en primer plano. Se decía que otras tareas estaban suspendidas (detenidas) o ejecutándose en segundo plano .

Hashing de ruta

El hash de rutas 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 encuentra el archivo o se queda sin posibilidades, el shell C consulta una tabla hash interna creada mediante el escaneo de los directorios de ruta. Esa tabla generalmente puede indicarle al shell C dónde encontrar el archivo (si existe) sin tener que buscar y se puede actualizar con el rehashcomando.

Descripción general del lenguaje

El shell C opera con una línea a la vez. Cada línea se convierte en un conjunto de palabras separadas por espacios u otros caracteres con un significado especial, incluidos paréntesis, operadores de canalización y de redirección de entrada/salida, punto y coma y símbolos &.

Declaraciones básicas

Una sentencia básica es aquella que simplemente ejecuta un comando. La primera palabra se toma como nombre del comando que se va a ejecutar y puede ser un comando interno, por ejemplo, echoo un comando externo. El resto de las palabras se pasan como argumentos al comando.

A nivel de enunciado básico, aquí se presentan algunas de las características de la gramática:

Comodín

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 archivo que coinciden (ver globbing ).

  • *coincide con cualquier número de caracteres.
  • ?coincide con cualquier caracter individual.
  • [... ]coincide con cualquiera de los caracteres dentro de los corchetes. Se permiten rangos, utilizando el guion.
  • [^... ]coincide con cualquier carácter que no esté en el conjunto.

El shell C también introdujo varias conveniencias de notación (a veces conocidas como globbing extendido ), que luego fueron copiadas 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.
  • ~usersignifica el directorio de inicio del usuario .

Se admiten varios comodines a nivel de directorio, por ejemplo, " */*.c".

Desde la versión 6.17.01, el uso de comodines recursivos como zsh (por ejemplo, " **/*.c" o " ***/*.html") también se admite con la globstaropción.

Darle al shell la responsabilidad de interpretar los comodines fue una decisión importante en Unix. Significaba que los comodines funcionarían con cada comando, y siempre de la misma manera. Sin embargo, la decisión dependía de la capacidad de Unix de pasar largas listas de argumentos de manera eficiente a través de la llamada al sistema exec que csh usa para ejecutar comandos. Por el contrario, en Windows , la interpretación de comodines la realiza convencionalmente cada aplicación. Esto 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 por parte del símbolo del sistema de DOS fuera poco práctico. Aunque el Windows moderno puede pasar líneas de comando de hasta aproximadamente 32K caracteres Unicode , la carga de la interpretación de comodines recae en la aplicación.

Redirección de E/S

De manera predeterminada, cuando csh ejecuta un comando, el comando hereda los controladores de 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 en su lugar para la entrada o la salida.

  • > archivo significa que la salida estándar se escribirá en el archivo , sobrescribiéndolo si existe y creándolo si no existe. Los errores siguen apareciendo en la ventana del shell.
  • >& archivo significa que tanto stdout como stderr se escribirán en el archivo , sobrescribiéndolo si existe y creándolo si no existe.
  • >> archivo significa que stdout se agregará al final del archivo .
  • >>& archivo significa que tanto stdout como stderr se agregarán al final del archivo .
  • < archivo significa que la entrada estándar se leerá desde el archivo .
  • << string es un documento here . Stdin leerá las siguientes líneas hasta la que coincida con string .

Redirigir stderr por sí solo no es posible sin la ayuda de un sub-shell.

establecer filtro  =  "$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 alternativa.

(  (  (  echo ok ;  ''  ) > /dev/fd/0 ) >& /dev/null < /dev/fd/1 ) | (  echo  "$<"  adiós  )

Unión

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.

Tubería

Los comandos se pueden conectar mediante una tubería, lo que hace que la salida de un comando se transfiera a la entrada del siguiente. Ambos comandos se ejecutan simultáneamente .

  • |Significa conectar la salida estándar a la entrada estándar del siguiente comando. Aún aparecen errores 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 de varios núcleos (varios procesadores), los comandos canalizados pueden ejecutarse literalmente al mismo tiempo, de lo contrario, el programador del sistema operativo divide el tiempo entre ellos.

Dado un comando, p. ej., " a | b", el shell crea una tubería , luego inicia ambos ay 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 almacenamiento en búfer de modo que ase pueda escribir durante un tiempo antes de que la tubería se llene, pero una vez que la tubería se llena, cualquier nueva escritura se bloqueará dentro del SO hasta que bse lean lo suficiente para desbloquear nuevas escrituras. Si bintenta leer más datos de los disponibles, se bloqueará hasta que ahaya escrito más datos o hasta que la tubería se cierre, p. ej., si asale.

Sustitución de variables

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 a la referencia, permiten la edición de 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 que de otro modo serían 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 se toman como literales, pero se siguen realizando sustituciones de variables y comandos.
  • 'La cadena' es una comilla fuerte. La cadena completa que la encierra se toma como literal.

Las comillas dobles dentro de comillas dobles deben ir precedidas de "\"". Lo mismo se aplica al símbolo del dólar, para evitar la expansión de variables "\$". En el caso de las comillas invertidas, para evitar la anidación de sustituciones 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.

  • `comando` significa tomar la salida del comando , analizarla 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 " \"\\\"\\\\\\\"\\\\\\\\\\\\\\\ "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\`\\\\\\\\\\\\\\\"\ \\\\\\"\\\"\" "contraseña" \"\\\"\\\\\\\"\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\\\\\\ \\\\\\\\\\\`\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\`\\\\\\ \\\\\\\\\"\\\\\\\"\\\\\\\`\\\\\\"\\\"\\\`\\\"\"\` \" "`"

Ejecución en segundo plano

Normalmente, cuando el shell C inicia un comando, espera a que el comando finalice antes de darle al usuario otro mensaje indicando que se puede escribir un nuevo comando.

  • Comando & significa iniciar un comando en segundo plano y solicitar inmediatamente un nuevo comando.

Subcapas

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.

Estructuras de control

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 sentencias if y switch. Las estructuras de control de la iteración son las sentencias while, foreach y repeat.

Declaración if

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.

 comando if ( expresión )

La forma larga 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 de lo contrario si  ( expresión2 )  entonces  comandos ...los demás  comandos terminan si

Si las palabras clave else y if aparecen en la misma línea, csh las encadena, en lugar de anidarlas, y el bloque termina con un único endif.

declaración de cambio

La sentencia switch compara una cadena con una lista de patrones, que puede contener caracteres comodín. Si no hay coincidencias, se toma la acción predeterminada, si la hay.

switch  ( cadena ) patrón  de caso 1: Comandos  Patrón de caso breaksw2 : Comandos romper ... por defecto : Comandos rompe y termina

mientras que la declaración

La instrucción while evalúa una expresión. Si es verdadera, el shell ejecuta los comandos anidados y luego repite el proceso mientras la expresión siga siendo verdadera.

mientras  ( expresión ) Comandosfin

Declaración foreach

La declaración foreach toma una lista de valores, generalmente una lista de nombres de archivos producidos 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

repetir declaración

La declaración de repetición repite un solo comando un número entero de veces.

Comando de repetición de números enteros

Variables

El shell C implementa tanto variables de shell como de entorno . [14] Las variables de entorno, creadas mediante la setenvdeclaración, son siempre cadenas simples, pasadas a cualquier proceso secundario , que recupera estas variables a través del envp[]argumento a main().

Las variables de shell, creadas mediante las instrucciones setor @, son internas de C shell. No se pasan a los procesos secundarios. Las variables de shell pueden ser cadenas simples o matrices de cadenas. Algunas de las variables de shell están predefinidas y se utilizan para controlar varias opciones internas de C shell, 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, incluso 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 para contener 1024 elementos. set fixed  =  { , }{ , } { , } { , }{ , }{ , } { , }{ , }{ , }

Expresiones

El shell 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 de sus operandos por espacios en blanco. Las variables se referencian como $name .

La precedencia de operadores también se tomó 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 con la misma precedencia. En C, la asociatividad es de izquierda a derecha para la mayoría de los operadores; en C shell, 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 0

Los paréntesis en el ejemplo de C shell se utilizan para evitar que los operadores de desplazamiento de bits se confundan con operadores de redirección de E/S. En ambos lenguajes, los paréntesis siempre se pueden utilizar para especificar explícitamente el orden de evaluación deseado, aunque sea solo por claridad.

Los valores de retorno están limitados a 8 bits. En el caso de exitlas expresiones, se puede utilizar el operador de negación unario para la evaluación de 32 bits.

salir  !! 256 # Devuelve 1.

Recepción

Aunque el propio Stephen Bourne reconoció que csh era superior a su shell para uso interactivo, [15] nunca ha sido tan popular para 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 la 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 a Unix, pero sh sí, lo que lo convirtió en una mejor opción para cualquier script que pudiera tener que ejecutarse en otras máquinas. A mediados de la década de 1990, csh estaba ampliamente disponible, pero el uso de csh para scripting se enfrentó a nuevas críticas por parte del comité POSIX , [17] que especificó que solo debería haber un shell preferido, KornShell , tanto para fines interactivos como de scripting. El C shell también se enfrentó a críticas de otros [18] [19] sobre los supuestos defectos del C shell en la sintaxis, las características faltantes y la mala implementación.

  • Defectos de sintaxis: eran, en general, inconsistencias simples pero innecesarias en la definición del lenguaje. Por ejemplo, los comandos set, setenvy aliashacían básicamente lo mismo, es decir, asociaban un nombre con una cadena o un conjunto de palabras. Pero los tres tenían diferencias leves pero innecesarias. Se requería un signo igual para a setpero no para setenvo alias; se requerían paréntesis alrededor de una lista de palabras para a setpero no para setenvo alias, etc. De manera similar, las construcciones de bucle if, switchy usan palabras clave innecesariamente diferentes ( endif, endswy end) para terminar los bloques anidados.
  • Características faltantes: las más citadas son la falta de capacidad para manipular los manejadores de archivos stdio de forma independiente y la compatibilidad con funciones. Aunque no se admite la 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 preceder a una barra invertida (el final de la última línea debe preceder a una comilla simple para delimitar el final del alias). La recursión es más favorable que los alias en los scripts como solución alternativa para las funciones (a continuación se ofrece un ejemplo).
  • La implementación, que utilizaba un analizador ad hoc , ha suscitado las críticas más serias. A principios de la década de 1970, la tecnología de compilación estaba lo suficientemente madura [20] como para que la mayoría de las nuevas implementaciones de lenguajes utilizaran un analizador de arriba hacia abajo o de abajo hacia arriba capaz de reconocer una gramática completamente recursiva . No se sabe por qué se eligió un diseño ad hoc para el shell C. Puede ser simplemente que, como dijo Joy en una entrevista en 2009, "Cuando comencé a hacer estas cosas con Unix, no era un muy buen programador". [21] El diseño ad hoc significaba que el lenguaje C shell no era completamente recursivo. Había un límite a la complejidad de los comandos que podía manejar.

Funcionó para la mayoría de los comandos escritos de forma interactiva, pero para los comandos más complejos que un usuario podría escribir en un script, podría fallar fácilmente, produciendo solo un mensaje de error críptico o un resultado no deseado. Por ejemplo, el shell C no podía soportar la canalización entre estructuras de control. Intentar canalizar la salida de un foreachcomando grepsimplemente no funcionaba. (La solución alternativa, que funciona para muchas de las quejas relacionadas con el analizador, es dividir el código en scripts separados. Si foreachse mueve a un script separado, la canalización funciona porque los scripts se ejecutan bifurcando una nueva copia de csh que hereda los manejadores stdio correctos. También es posible romper códigos en un solo archivo. A continuación se ofrece un ejemplo sobre cómo romper códigos en un solo archivo).

Otro ejemplo es el comportamiento no deseado de los siguientes fragmentos. Ambos parecen significar: "Si 'myfile' no existe, créelo escribiendo 'mytext' 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 myfile ) entonces echo mytext > myfile          fin si
# Siempre crea un archivo vacío si  ( ! -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 existe.

La implementación también es criticada por sus mensajes de error notoriamente pobres, por ejemplo, "0: Evento no encontrado", que no brinda información útil sobre el problema.

Sin embargo, con 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" implica 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 'Ingrese 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]"         

Es preferible romper códigos recurriendo el script como solución alternativa para las funciones.

#!/bin/csh -f if  (  ! "$?main"  )  then  if  (  ! "$?0"  )  then echo 'Debe 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 endif             ir a  "$1"  ;  cambiarmifunción:función myfunc2echo  "Una función." salirmifunc2:echo  "Otra función." salir

Influencia

Hamilton C shell de 64 bits en un escritorio de Windows 7 .

El shell C tuvo un gran éxito al introducir una gran cantidad de innovaciones, entre ellas el mecanismo de historial, los alias, la notación de tilde, la finalización interactiva de nombres de archivo, una gramática de expresiones incorporada al 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 independientemente, incluidos ksh y bash , solo se conocen dos clones de csh. (Dado que tcsh se basó en el código csh escrito originalmente por Bill Joy, no se lo considera un clon).

En 1986, Allen Holub escribió On Command: Writing a Unix-Like Shell for MS-DOS [22], un libro que describía 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 de sh. Los disquetes complementarios que contenían el código fuente completo de SH y de un conjunto básico de utilidades similares a Unix (cat, cp, grep, etc.) estaban disponibles por 25 y 30 dólares, respectivamente, a través 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 shell C.

En 1988, Hamilton Laboratories comenzó a distribuir Hamilton C shell para OS/2 . [23] Incluía tanto un clon de csh como un conjunto de utilidades similares a Unix. En 1992, Hamilton C shell fue lanzado para Windows NT . [24] La versión de Windows continúa siendo compatible activamente, pero la versión de OS/2 se suspendió en 2003. [24] Una referencia rápida de principios de 1990 [25] describió la intención como "plena conformidad con todo el lenguaje C shell (excepto el control de tareas)" 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 de arriba hacia abajo que permitía que las estructuras de control se anidaran o canalizaran, algo que el C shell original no podía soportar, dado su analizador ad hoc. Hamilton también agregó nuevas características del lenguaje, incluidos 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, al configurar una tubería.

Véase también

Referencias

  1. ^ Zoulas, Christos (24 de noviembre de 2016). «¡El tcsh-6.20.00 ya está disponible!». mx.gw.com . Archivado desde el original el 25 de noviembre de 2016. Consultado el 24 de noviembre de 2016 .
  2. ^ Harley Hahn, Guía de Harley Hahn para Unix y Linux Archivado el 24 de agosto de 2019 en Wayback Machine .
  3. ^ Berkeley Engineering Lab Notes, Volumen 1, Número 2, octubre de 2001 Archivado el 9 de julio de 2010 en Wayback Machine .
  4. ^ Introducción al C shell Archivado el 13 de julio de 2018 en Wayback Machine por Bill Joy .
  5. ^ Ubuntu - Detalles del paquete csh. Packages.ubuntu.com.
  6. ^ Debian - Detalles del paquete csh. Packages.debian.org.
  7. ^ Ubuntu - Detalles del paquete tcsh. Packages.ubuntu.com.
  8. ^ Debian - Detalles del paquete tcsh. Packages.debian.org.
  9. ^ Ken Greer (3 de octubre de 1983). "C shell con reconocimiento y finalización de comandos y nombres de archivo". Grupo de noticias : net.sources . Consultado el 29 de diciembre de 2010 .
  10. ^ Página del manual tcsh(1). tcsh.
  11. ^ Corrige el archivo en tcsh-17 de junio de 2000.
  12. ^ 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.
  13. ^ Se pronuncia "bang, bang"
  14. ^ Troy, Douglas (1990). Sistemas UNIX . Fundamentos de computación. Benjamin/Cumming Publishing Company. pág. 25.
  15. ^ Bourne, Stephen R. (octubre de 1983). "The Unix Shell". BYTE . p. 187 . Consultado el 30 de enero de 2015 .
  16. ^ La guía privilegiada del universo (PDF) . Charles River Data Systems, Inc. 1983. pág. 13.
  17. ^ Estándar 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 . 
  18. ^ Tom Christiansen considera que la programación CSH es perjudicial
  19. ^ Diez razones principales para no utilizar el C-shell por Bruce Barnett
  20. ^ David Gries (1971). Construcción de compiladores para computadoras digitales. John Wiley & Sons. ISBN 0-471-32776-X . 
  21. ^ Bill Joy en conversación con Brent Schlender, Churchill Club, Santa Clara, CA, 11 de febrero de 2009 [usurpado] .
  22. ^ 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.
  23. ^ Hamilton, Douglas. "Anuncio de Hamilton C shell" (PDF) . IBM Personal Systems Developer (verano de 1989): 119–121 . Consultado el 11 de julio de 2020 .
  24. ^ ab 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 . Consultado el 3 de abril de 2018 .
  25. ^ Referencia rápida de la capa C de Hamilton (PDF) . Hamilton Laboratories, Wayland, MA. 1988–1990 . Consultado el 11 de julio de 2020 .

Lectura adicional

  • Anderson, Gail; Paul Anderson (1986). Guía de campo de UNIX C Shell. 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). Referencia de escritorio de UNIX C Shell . John Wiley & Sons. ISBN 0-471-55680-7.
  • "Introducción a la programación en C Shell". Departamento de Informática de Canisius College . Consultado el 23 de junio de 2010 .
  • Una introducción al C shell por William Joy .
  • Linux en pocas palabras: Capítulo 8. csh y tcsh.
  • Página de inicio de tcsh.
  • Página del manual tcsh(1).
  • Código fuente tcsh más reciente disponible.
  • Código fuente histórico csh de 2BSD con fecha del 2 de febrero de 1980.
  • El árbol Unix, distribuciones Unix históricas completas.
  • La programación Csh se considera dañina.
  • Diez razones principales para no utilizar el C Shell.
Obtenido de "https://es.wikipedia.org/w/index.php?title=C_shell&oldid=1247058906"