¿Por qué no se permiten los nombres de funciones numéricas?

10

Considera lo siguiente:

$ ksh -c '1(){ echo hi;};1'
ksh: 1: invalid function name
$ dash -c '1(){ echo hi;};1'
dash: 1: Syntax error: Bad function name
$ bash -c '1(){ echo hi;};1'
bash: `1': not a valid identifier
bash: 1: command not found
$ mksh -c '1(){ echo hi;};1'
hi

Básicamente, estaba tratando de declarar funciones 1y 0cuáles serían shorthands para truey false, pero como puede ver, tuve problemas con el uso de nombres numéricos en las funciones. El mismo comportamiento ocurre con alias y nombres de dos dígitos.

La pregunta es "¿por qué"? ¿Es obligatorio por POSIX? o simplemente un capricho de conchas de bourne?

Ver también la pregunta relacionada con este.

Sergiy Kolodyazhnyy
fuente
1
Las cosas ordenadas por posix son en su mayoría caprichos de conchas tipo Bourne. : P
muru
Veo lo que hiciste alli . . . > :) lol
Sergiy Kolodyazhnyy
44
@fkraiem Consulte meta.askubuntu.com/q/13807/295286 Los shells / shell scripting son y siempre han sido tema en Ask Ubuntu :) Es un tema esencial para la administración adecuada del sistema de cualquier sistema Ubuntu
Sergiy Kolodyazhnyy
44
Vale la pena señalar que 0está trueen la secuencia de comandos de shell y 1es false(realmente, cualquier no distinto de cero se trata como falso), en caso de que alguien que lea esto no lo sepa. Esto es al revés de la mayoría de los otros lenguajes de programación.
Ethan Kaminski el
2
@ EthanKaminski sí, en cuanto a los estados de salida de los comandos , eso es absolutamente cierto. El valor de retorno de 0 está trueen shell. Sin embargo, en la expansión aritmética, los $((...))estados de retorno se cambian: 1 es truey 0 es falsepara mantener la coherencia con la sintaxis del lenguaje C. Intente, por ejemplo, bash -c 'echo $((1==1));echo $((1==2))' lo que estaba tratando de hacer fuera de esta pregunta era en realidad "revertir" el comportamiento. Vea el último ejemplo de mi respuesta aquí para ver exactamente qué estaba tratando de hacer. Idea tonta, pero no obstante funciona
Sergiy Kolodyazhnyy

Respuestas:

14

POSIX dice:

2.9.5 Comando de definición de funciones

Una función es un nombre definido por el usuario que se usa como un comando simple para llamar a un comando compuesto con nuevos parámetros posicionales. Una función se define con un "comando de definición de función".

El formato de un comando de definición de función es el siguiente:

 fname ( ) compound-command [io-redirect ...]

La función se llama fname ; la aplicación se asegurará de que sea un nombre (ver Nombre XBD ) y que no sea el nombre de una utilidad incorporada especial. Una implementación puede permitir otros caracteres en el nombre de una función como una extensión. La implementación mantendrá espacios de nombres separados para funciones y variables.

Y:

3.235 Nombre

En el lenguaje de comandos de shell, una palabra que consiste únicamente en guiones bajos, dígitos y alfabéticos del juego de caracteres portátil. El primer carácter de un nombre no es un dígito.

Nota: El juego de caracteres portátil se define en detalle en Juego de caracteres portátil.

Por lo tanto, una palabra que comienza con un dígito no puede ser un nombre de función.

muru
fuente
Aún así, POSIX no dice por qué, pero lo tomaré como la respuesta "Porque los estándares". Gracias
Sergiy Kolodyazhnyy
44
@SergiyKolodyazhnyy Diría que es algo heredado. Este estándar para nombres también es bastante común en otras cosas (los nombres de IIRC C también siguen el mismo estándar), por lo que probablemente sea una cosa de Unix. Además, en C, hace que sea más fácil analizarlo
muru
3
@muru en C traería cierta ambigüedad si se permitiera. Por ejemplo, ¿qué 1Lsignificaría? ¿Un nombre de función? O un long intliteral?
Ruslan
2
Además de lo anterior, vale la pena señalar que en C, un nombre de función desnudo puede actuar como un puntero a esa función. Esto le permite pasar funciones como parámetros a una función, almacenar referencias a ellas en variables, etc. A menudo se usa para devoluciones de llamada. Esto contrasta con el nombre de la función seguido (), posiblemente con argumentos dentro, que denota una llamada a la función en cuestión (y toma el valor que devuelve la función que se llama). Entonces, si tiene una función int f() { return 42; }en C, fes válida en un contexto de puntero y f()es válida en un contexto entero sin puntero.
un CVn
13

Ese es un estándar en muchos idiomas para evitar la confusión entre operaciones matemáticas y variables o funciones o métodos.

Considerar:

var 1 = 100

print 1*10 //should return 10 but would instead return 1000

var x = 5
x += 1
print x //returns 105, not 6    

def 100(num)
  return num * 1000
end

var y = 10 + 100(10)
print y // returns 100010 instead of 1010

Como puede ver, si se permitieran los números como nombres de variables o funciones, hacer cálculos matemáticos más adelante en un programa podría volverse muy confuso y tendría que encontrar soluciones creativas si necesitara hacer cálculos matemáticos con esos números más adelante. También puede producir resultados inesperados en algunos idiomas. Imagine que está incrementando un número para un bucle pero uno de los dígitos ya es una variable que equivale a una cadena. Inmediatamente arrojaría un error. Si no fue el autor original del código, ese error podría tardar bastante en encontrarlo.

En pocas palabras, esta es la razón por la cual la mayoría de los idiomas no le permiten usar un número como el nombre de una variable o función o método, etc.

Josh
fuente
Iba a comentar "pero las variables en shell deben anteponerse $para expandirse", pero de nuevo, si shell está inspirado en otros lenguajes, está bien, supongo, además, en expansión aritmética ((, no se requiere que las variables tengan encabezado $. OK, puedo entender eso
Sergiy Kolodyazhnyy
3
Sí, es una convención porque creará resultados inesperados en casi todos los idiomas, pero, incluso en una situación en la que funcionaría, puede hacer que el código sea muy difícil de comprender para cualquiera que tenga que trabajar en su código después de usted.
Josh el
2
La expansión aritmética @SergiyKolodyazhnyy permite hacer referencia a nombres de variables sin $, así que eso es todo. Pero eso es probablemente secundario a la otra razón de "simplemente seguir una convención común"
hobbs
@hobbs sí, estoy totalmente de acuerdo con eso
Sergiy Kolodyazhnyy
1
Esta explicación de "la mayoría de los idiomas" tiene poco sentido para las conchas. Todos los del estilo Bourne tienen parámetros cuyos nombres parecerse literales u operadores numéricos: 0el nombre o secuencia de comandos shell, 1, 2, ..., para los parámetros de posición, *para ellos se unieron, -para las opciones habilitadas, ?para el último estado de salida, y !para la PID del trabajo asincrónico más reciente. (Por lo tanto, incluso en $(( )), a $menudo se necesita). El código que se muestra aquí para demostrar la razón sugerida no es un script para ningún shell de estilo Bourne, ya que no hay forma de demostrarlo de esa manera, ya que no se aplica a ellos.
Eliah Kagan
10

En C, considere una expresión como:

1000l + 2.0f;

¿Es 1000luna variable o una constante? Debido a que los nombres de las variables no pueden comenzar con un dígito, tiene que ser una constante. Esto hace que el análisis sea más fácil y estricto (los errores tipográficos 1000kse pueden detectar fácilmente). También es más fácil tener una sola regla para variables y nombres de funciones, ya que las funciones también pueden tratarse como variables. Ahora, por supuesto, los analizadores son mucho más complejos y potentes, y tenemos cosas como literales personalizados en C ++. Pero en aquellos viejos tiempos de la prehistoria, sacrificar un poco de flexibilidad innecesaria podría hacer que su compilación (o interpretación) sea mucho más corta (y la gente aún se queja de los tiempos de compilación de C ++).

Y puede ver los efectos de una influencia de C en todo el lenguaje de shell, por lo que no es sorprendente que el shell Bourne (o C shell) y, por lo tanto, POSIX, hayan restringido la clase de nombres permitidos a la misma que C.

Olorin
fuente
2
Como explican , esta es la correcta. Es sin que las mismas consideraciones se aplican a todos los idiomas o que los del estilo Bourne tienen una sintaxis similar a la de C, pero que la cultura asociada a C era fuerte y diseñadores de concha tenido que llegar a algunas garantías con respecto a cuáles serían los identificadores permitido. Creo que esto podría usar ejemplos de "se pueden ver los efectos de una influencia de C en todo el lenguaje shell", ya que las similitudes entre ellos realmente no superan las diferencias (piense en qué números se consideran verdaderos , por ejemplo). No obstante, esta respuesta es correcta.
Eliah Kagan el
Podría decirse que @Eliah lo de los números también es una consecuencia directa de los estados de salida para el éxito y el fracaso en C, por lo que tiendo a pensar en términos de éxito y fracaso en lugar de verdadero y falso al escribir pruebas de shell. Tienes razón en que mucha sintaxis de shell no se parece en nada a C, pero los ejemplos incluyen las llaves, los puntos y comas, el cortocircuito &&y ||la falta de soporte para el nulo ASCII en cadenas,
Olorin