@kkachu explicou melhor do que eu poderia. Vou apenas adicionar uma nota de histórico.
O shell que veio com as primeiras versões do Unix (mais tarde chamado de shell Thompson) não tinha nenhuma variável, mas você já podia escrever scripts simples que usassem parâmetros.
sh [ name [ arg1 ... [ arg9 ] ] ] The name is the name of a file which will be read and in‐ terpreted. If not given, this subinstance of the shell will continue to read the standard input file. In command lines in the file (not in command input), character sequences of the form "$n", where n is a digit 0, ..., 9, are replaced by the nth argument to the invo‐ cation of the shell (argn). "$0" is replaced by name.
$1 ... $n já eram os argumentos e $0 o nome do script (não o
1º argumento), mas não foram chamados parâmetros posicionais .
Observe que, naquela época, $1 foi literalmente substituído pelo primeiro argumento antes da interpretação do shell.
Por exemplo, um script que tinha:
echo $1
chamado como
sh script 'foo; echo bar'
executaria echo foo; echo bar . Esse shell era muito simples, escrito para computadores com poucas centenas de kilobytes de memória.
A shell Bourne chegou quase uma década depois (no final dos anos 70) com uma versão do Unix que introduziu o ambiente e outras coisas boas.
O shell Bourne veio com variáveis e muito mais construções de programação.
A terminologia parâmetro posicional , pelo menos quando se trata de shells Unix, foi introduzida pelo shell Bourne, e referenciada à mesma coisa, $1 ... $n para os argumentos do script (e $0 ainda é o nome do script). Como no shell Thompson, você poderia se referir apenas aos primeiros 9 argumentos ( $1 to $9 ) com parâmetros posicionais (mas use shift ou "$@" ou for i do loops para acessar o restante) (e isso também explica (portabilidade para trás) porque você precisa de ${10} em vez de $10 nas implementações mais modernas de sh para as 10 primeiras).
Desta vez, sh script 'foo; echo bar' não causou mais que echo bar seja executado, mas mesmo assim o Bourne shell introduziu o infame split + glob, eu suponho não quebrar muito compatível com o shell Thompson, então script 'foo *' script tem echo $1 ainda chamou echo com foo e a lista de arquivos no diretório atual como argumentos (como no shell Thompson, mas desta vez através de um mecanismo diferente).
scripts também foram chamados de procedimentos de shell (note que o shell Bourne ainda não tem funções):
2.0 Shell procedures The shell may be used to read and execute commands contained in a file. For example, sh file [ args ] calls the shell to read commands from file. Such a file is called a command procedure or shell procedure. Arguments may be supplied with the call and are referred to in file using the positional parameters $1, $2...
As funções foram introduzidas pela primeira vez no shell Korn (baseado no shell Bourne) no início dos anos 80 com um
function foo {
...
}
sintaxe.
Funções foram eventualmente adicionadas ao shell Bourne, mais tarde, em SysVR2 (1984), com uma sintaxe diferente:
foo() any-command
(mas com comportamento inesperado quando any-command era um comando simples e tinha redirecionamentos que provavelmente é a razão pela qual o POSIX requer apenas comandos compostos (como { ...; } o mais usado) ser reconhecido lá para o POSIX sh ).
No shell Korn e Bourne, $0 na função ainda era o nome do script, não o nome da função (enquanto os parâmetros $1 , $2 posicional se referem aos argumentos da função).
Isso mudou em ksh93 para o estilo function f { da definição da função, onde $0 se torna o nome da função na função.
Em zsh , $0 é o nome da função, como em ksh93. zsh também introduziu funções anônimas com o seguinte:
function { echo $1, $2; } foo bar
ou
(){ echo $1, $2; } foo bar
sintaxe, em que $0 se torna (anon) (ou fica com o nome do script com set +o functionargzero , como quando em sh / ksh emulation).
Em zsh , como em csh , os argumentos dos scripts também estão na matriz $argv , o que levanta a confusão sobre o nome do programa chamado de forma semelhante aos argumentos.
Lá, você pode atribuir valores aos parâmetros de posição com:
argv[1]=value
ou
1=value
(e também 0=newprogramname para alterar o nome do programa).
Em outros shells semelhantes a Bourne, você precisa usar set para atribuir todos de uma só vez:
set -- arg1 arg2
E você não pode alterar $0 .
Em rc (pelo menos a porta Unix), você não pode fazer:
1 = value
Mas você pode fazer:
* = (arg1 arg2)
para definir os parâmetros posicionais. Você não pode alterar $0 em rc , mas você pode em seu derivado es com 0=newprogramname como em zsh .
TL; DR
O $1 , $2 ... para se referir aos argumentos dos scripts vem do shell Thompson, mas ainda não foram chamados parâmetros posicionais . E $0 (provavelmente escolhido em referência a argv[0] como @ikkachu bem colocado) refere-se ao nome do script.
O termo parâmetros posicionais vem do shell Bourne.
$0 não é um parâmetro posicional porque não se refere a um argumento do script. Refere-se ao nome do script (ou ao shell argv[0] quando o shell não executa nenhum script).