Por que nomes de funções numéricos não são permitidos?

10

Considere o seguinte:

$ 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

Basicamente, eu estava tentando declarar funções 1e 0quais seriam atalhos para truee false, mas como você pode ver, tive um problema ao usar nomes numéricos em funções. O mesmo comportamento ocorre com aliases e nomes de dois dígitos.

A pergunta é "por que"? É mandatado pelo POSIX? ou apenas uma peculiaridade de conchas tipo bourne?

Veja também a pergunta relacionada a este.

Sergiy Kolodyazhnyy
fonte
1
As coisas que são mandatadas pelo posix são, na maioria das vezes, peculiaridades de conchas tipo Bourne. : P
muru 19/11/19
Eu vi o que você fez lá . . . > :) lol
Sergiy Kolodyazhnyy
4
@fkraiem Por favor, consulte meta.askubuntu.com/q/13807/295286 Os scripts de shell / shell estão e sempre estiveram no tópico Ask Ask :) É um tópico essencial para a administração adequada do sistema de qualquer sistema Ubuntu
Sergiy Kolodyazhnyy
4
Vale a pena notar que 0está trueno script de shell e 1é false(realmente, qualquer diferente de zero é tratado como falso), caso alguém que esteja lendo isso não saiba. Isso é inverso da maioria das outras linguagens de programação.
2
@ EthanKaminski sim, tanto quanto os status de saída dos comandos , isso é absolutamente verdade. O valor de retorno 0 está trueno shell. No entanto, na expansão aritmética, os $((...))status de retorno são invertidos - 1 é truee 0 é falseconsistente com a sintaxe da linguagem C. Tente, por exemplo, o bash -c 'echo $((1==1));echo $((1==2))' que eu estava tentando fazer fora desta questão era, na verdade, "reverter" o comportamento. Veja o último exemplo da minha resposta aqui para ver o que exatamente eu estava tentando fazer. Parva ideia, mas mesmo assim funciona
Sergiy Kolodyazhnyy

Respostas:

14

O POSIX diz:

2.9.5 Comando de definição de função

Uma função é um nome definido pelo usuário que é usado como um comando simples para chamar um comando composto com novos parâmetros posicionais. Uma função é definida com um "comando de definição de função".

O formato de um comando de definição de função é o seguinte:

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

A função é nomeada fname ; o aplicativo deve garantir que seja um nome (consulte Nome XBD ) e que não seja o nome de um utilitário interno especial. Uma implementação pode permitir outros caracteres no nome de uma função como uma extensão. A implementação deve manter espaços de nomes separados para funções e variáveis.

E:

3.235 Nome

Na linguagem de comando do shell, uma palavra que consiste apenas em sublinhados, dígitos e alfabéticos do conjunto de caracteres portátil. O primeiro caractere de um nome não é um dígito.

Nota: O Portable Character Set é definido em detalhes no Portable Character Set.

Portanto, uma palavra que começa com um dígito não pode ser um nome de função.

muru
fonte
Ainda assim, o POSIX não diz exatamente o porquê, mas vou levá-lo como resposta "Porque os padrões". Obrigado
Sergiy Kolodyazhnyy
4
@SergiyKolodyazhnyy Eu diria que é uma coisa herdada. Esse padrão para nomes também é bastante comum em outras coisas (os nomes C do IIRC também seguem o mesmo padrão), então provavelmente é uma coisa do Unix. Além disso, em C, torna-se mais fácil de analisar
Muru
3
O @muru em C traria alguma ambiguidade se fosse permitido. Por exemplo, o que 1Lsignificaria? Um nome de função? Ou um long intliteral?
Ruslan
2
Além disso, vale a pena notar que em C, um nome de função simples pode atuar como um ponteiro para essa função. Isso permite que você passe funções como parâmetros para uma função, armazene referências a elas em variáveis, etc. Geralmente usado para retornos de chamada. Isso contrasta com o nome da função seguido por (), possivelmente com argumentos internos, o que indica uma chamada para a função em questão (e assume o valor retornado pela função que está sendo chamada). Portanto, se você tem uma função int f() { return 42; }em C, fé válida em um contexto de ponteiro e f()é válida em um contexto inteiro sem ponteiro.
um CVn
13

Esse é um padrão em muitas línguas para evitar confusão entre operações matemáticas e variáveis ​​ou funções ou 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 você pode ver, se os números fossem permitidos como nomes de variáveis ​​ou funções, fazer matemática posteriormente em um programa pode se tornar muito confuso e você teria que criar soluções alternativas criativas se realmente precisasse fazer matemática com esses números mais tarde. Também pode produzir resultados inesperados em alguns idiomas. Imagine que você está incrementando um número para um loop, mas um dos dígitos já é uma variável igual a uma string. Isso geraria imediatamente um erro. Se você não era o autor original do código, esse erro poderia demorar um pouco para ser encontrado.

Em poucas palavras, é por isso que a maioria dos idiomas não permite que você use um número como o nome de uma variável, função, método ou etc.

Josh
fonte
Eu ia comentar "mas as variáveis ​​no shell precisam ser anexadas $para serem expandidas", mas se o shell for inspirado em outras linguagens, tudo bem, eu acho, além disso, nas ((variáveis ​​de expansão aritmética não é necessário ter liderança $. OK, eu posso entender isso #
Sergiy Kolodyazhnyy 19/1117
3
Sim, é uma convenção, pois criará resultados inesperados em quase todos os idiomas, mas, mesmo em uma situação em que funcionaria, pode dificultar a compreensão do código para qualquer pessoa que precise trabalhar no seu código depois de você.
19417 Josh
2
A expansão aritmética do @SergiyKolodyazhnyy permite fazer referência a nomes de variáveis ​​sem $, então é isso. Mas isso é provavelmente secundário para o outro motivo de "apenas seguinte convenção comum"
hobbs
@hobbs sim, concordo absolutamente com isso #
Sergiy Kolodyazhnyy
1
Essa explicação da "maioria das línguas" faz pouco sentido para as conchas. Todos os shells Bourne-style ter parâmetros cujos nomes parecem com literais numéricos ou operadores: 0para o nome do shell ou script, 1, 2, ..., para parâmetros de posição, *para eles se juntaram, -para opções ativadas, ?para o último status de saída, e !para o PID do trabalho assíncrono mais recente. (Assim, mesmo em $(( )), $geralmente é necessário.) O código mostrado aqui para demonstrar a lógica sugerida não é um script para qualquer shell no estilo Bourne, pois não há como demonstrar dessa maneira, pois não se aplica a eles.
Elias Kagan
10

Em C, considere uma expressão como:

1000l + 2.0f;

É 1000luma variável ou uma constante? Como os nomes das variáveis ​​não podem começar com um dígito, deve ser uma constante. Isso torna a análise mais fácil e mais rigorosa (erros de digitação 1000kpodem ser facilmente capturados). Também é mais fácil ter uma regra única para variáveis ​​e nomes de funções, pois as funções também podem ser tratadas como variáveis. Agora , é claro, os analisadores são muito mais complexos e poderosos, e temos coisas como literais personalizados em C ++. Mas naqueles dias antigos da pré-história, sacrificar um pouco de flexibilidade desnecessária poderia tornar seus tempos de compilação (ou interpretação) muito mais curtos (e as pessoas ainda reclamam dos tempos de compilação em C ++).

E você pode ver os efeitos de uma influência C em toda a linguagem do shell, portanto, não é surpreendente que o shell Bourne (ou shell C) e, portanto, POSIX, tenha restringido a classe de nomes permitidos à mesma do C.

Olorin
fonte
2
Como explicações , esta é a correta. É não que as mesmas considerações se aplicam a todos os idiomas ou que shells Bourne-style tem uma sintaxe semelhante à de C, mas que a cultura associada a C era forte e designers de shell tinha que vir para cima com algumas garantias quanto ao que identificadores seria permitido. Eu acho que isso poderia usar exemplos de "você pode ver os efeitos de uma influência C em toda a linguagem shell", pois as semelhanças entre eles realmente não superam as diferenças (pense sobre quais números são considerados verdadeiros , por exemplo). No entanto, esta resposta está correta.
Elias Kagan
@Eliah, sem dúvida, a questão dos números também é uma conseqüência direta dos status de saída para o sucesso e o fracasso em C, então eu costumo pensar em termos de sucesso e fracasso, em vez de verdadeiro e falso ao escrever testes de shell. Você está certo de que a abundância de sintaxe do shell não se parece com C, mas os exemplos incluem chaves, ponto- &&e -vírgula, curto-circuito e ||falta de suporte para o nulo ASCII em strings,
Olorin