Variáveis de ambiente versus parâmetros posicionais
Antes de começarmos a discutir o $INTEGERtipo de variáveis, precisamos entender o que realmente são e como diferem das variáveis de ambiente. Variáveis como $INTEGERos chamados parâmetros posicionais. Isso está descrito no padrão POSIX (Interface do sistema operacional portátil), seção 2.1 (ênfase minha):
- O shell executa uma função (consulte Comando de Definição de Função), interno (consulte Utilitários Internos Especiais), arquivo executável ou script, fornecendo os nomes dos argumentos como parâmetros posicionais numerados de 1 a n e o nome do comando (ou no caso de uma função em um script, o nome do script) como o parâmetro posicional numerado 0 (consulte Pesquisa e execução de comandos).
Por outro lado, variáveis como $HOMEe $PATHsão variáveis de ambiente. Sua definição é descrita na seção 8 da norma :
As variáveis de ambiente definidas neste capítulo afetam a operação de vários utilitários, funções e aplicativos. Existem outras variáveis de ambiente que são de interesse apenas para utilitários específicos. As variáveis de ambiente que se aplicam apenas a um único utilitário são definidas como parte da descrição do utilitário.
Observe a descrição deles. Parâmetros posicionais devem aparecer na frente de um comando, ie command positional_arg_1 positional_arg_2.... Eles devem ser fornecidos pelo usuário para informar ao comando o que especificamente fazer. Quando você o fizer echo 'Hello' 'World', ele imprimirá as seqüências Helloe World, porque esses são parâmetros posicionais para echoas coisas nas quais você deseja echooperar. E echoé construído de tal forma que entende os parâmetros posicionais como strings a serem impressos (a menos que sejam um dos sinalizadores opcionais como -n). Se você fizer isso com um comando diferente, pode não entender o que HelloeWorldé porque talvez ele espere um número. Observe que os parâmetros posicionais não são "herdados" - um processo filho não conhece os parâmetros posicionais do pai, a menos que seja explicitamente passado ao processo filho. Freqüentemente, você vê parâmetros posicionais sendo passados com scripts de wrapper - aqueles que talvez verifiquem a instância de um comando já existente ou adicionem parâmetros posicionais adicionais ao comando real que será chamado.
Por outro lado, as variáveis de ambiente devem afetar vários programas. São variáveis de ambiente , porque estão definidas fora do próprio programa (mais sobre isso abaixo). Certas variáveis de ambiente, como HOMEou PATHpossuem formato específico, significado específico e terão o mesmo significado para cada programa. HOMEA variável terá o mesmo significado para qualquer utilitário externo /usr/bin/findou para o seu shell (e consequentemente para um script) - é o diretório inicial do nome de usuário sob o qual o processo é executado. Observe que variáveis ambientais podem ser usadas para explicar comportamentos de comandos específicos, por exemploUIDA variável de ambiente pode ser usada para verificar se o script é executado com privilégios de root ou não e se ramifica para ações específicas adequadamente. As variáveis de ambiente são herdáveis - os processos filhos obtêm uma cópia do ambiente dos pais. Consulte também Se os processos herdam o ambiente do pai, por que precisamos exportar?
Em resumo, a principal distinção é que as variáveis de ambiente são definidas fora do comando e não devem ser variadas (geralmente), enquanto parâmetros posicionais são coisas que devem ser processadas pelo comando e são alteradas.
Não apenas conceitos de shell
O que eu notei nos comentários é que você está misturando terminal e shell, e realmente recomendo que você leia sobre terminais reais que antes eram dispositivos físicos. Atualmente, o "terminal" ao qual estamos nos referindo normalmente, aquela janela com fundo preto e texto verde é na verdade software, um processo. Terminal é um programa que executa um shell, enquanto o shell também é um programa, mas aquele que lê o que você digita para executar (ou seja, se for um shell interativo; shells não interativos são scripts e sh -c 'echo foo'tipos de invocações). Mais sobre conchas aqui .
Essa é uma distinção importante, mas também é importante reconhecer que o terminal é um programa e, portanto, adere às mesmas regras de ambiente e parâmetros posicionais. Sua gnome-terminalquando iniciado vai olhar para sua SHELLvariável de ambiente, e desovar o shell padrão adequado para você, a menos que você especifique algum outro comando com -e. Digamos que mudei meu shell padrão para ksh - o gnome-terminal irá aparecer em kshvez de bash. Esse também é um exemplo de como o ambiente é usado pelos programas. Se eu disser explicitamente gnome-terminalcom -epara executar shell específico - ele vai fazê-lo, mas não vai ser permanente. Por outro lado, o ambiente deve permanecer inalterado (mais sobre isso posteriormente).
Portanto, como você pode ver, variáveis de ambiente e posicionais são propriedades de um processo / comando, não apenas shell. Quando se trata de shell scripts, eles também seguem o modelo que foi definido pela linguagem de programação C. Tomemos, por exemplo, a mainfunção C , que normalmente se parece com
int main(int argc, char **argv)
, onde argcestá o número de argumentos da linha de comando e argvé efetivamente um conjunto de parâmetros da linha de comando; depois, há uma environfunção (no Linux man -e 7 environ) de acessar coisas como o caminho do diretório inicial do usuário, a lista de diretórios nos PATHquais podemos procurar executáveis etc. Os scripts de shell também são modelados da mesma maneira. Na terminologia do shell, temos parâmetros posicionais $1, $2e assim por diante, enquanto $#é o número de parâmetros posicionais. Que tal $0? Esse é o nome do próprio executável, que também é modelado a partir da linguagem de programação C - argv[0]seria o nome do seu C "executável". E isso é verdade para a maioria das linguagens de programação e script .
Blocos interativos vs não interativos
Uma das coisas que eu já sugeri é a distinção entre shells interativos e não interativos . O prompt em que você digita os comandos - que é interativo, interage com o usuário. Por outro lado, quando você tem um script de shell ou executa bash -c''de forma não interativa.
E é aí que a distinção se torna importante. O shell que você já executa é um processo que foi gerado com parâmetros posicionais (para o bashshell de login é um "... cujo primeiro caractere do argumento zero é um - ou um iniciado com a opção --login".) ( Referência ) )
Por outro lado, scripts e shells lançados com a -copção podem aproveitar $1e $2argumentos. Por exemplo,
$ bash -c 'echo $1; stat $2' sh 'Hello World' /etc/passwd
Hello World
File: '/etc/passwd'
Size: 2913 Blocks: 8 IO Block: 4096 regular file
Device: 801h/2049d Inode: 6035604 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2017-08-12 14:48:37.125879962 -0600
Modify: 2017-08-12 14:48:37.125879962 -0600
Change: 2017-08-12 14:48:37.137879811 -0600
Birth: -
Observe que eu também usei shlá, porque uma pequena peculiaridade da -copção é pegar o primeiro parâmetro posicional e atribuí-lo $0, ao contrário de normalmente ser um nome do programa.
Outra coisa que é importante notar é que parâmetros posicionais são o que eu chamo de "framable". Observe como, lançamos pela primeira vez bashcom seus próprios parâmetros posicionais, mas esses parâmetros posicionais se tornaram parâmetros para echoe stat. E cada programa entende isso da sua maneira. Se dermos statuma string Hello Worlde não houver arquivo Hello World, isso produzirá um erro; bashtrata-o apenas como uma sequência simples, mas statespera que ela seja um nome de arquivo existente. Por outro lado, todos os programas concordariam que a variável de ambiente HOMEé um diretório (a menos que o programador a codificasse de maneira irracional).
Podemos mexer com variáveis de ambiente e parâmetros posicionais?
Tecnicamente, podemos mexer com ambos, mas não devemos mexer com variáveis de ambiente, enquanto geralmente precisamos fornecer parâmetros posicionais. Podemos executar comandos no shell anexando uma variável, por exemplo:
$ hello=world bash -c 'echo $hello'
world
Também podemos colocar variáveis no ambiente usando simplesmente export variable=valuedentro do shell ou script. Ou podemos executar um comando com ambiente completamente vazio com env -c command arg1 arg2. No entanto, normalmente não é recomendável mexer com o ambiente, especialmente usando variáveis maiúsculas ou substituindo as variáveis de ambiente já existentes. Observe que isso é recomendado, embora não seja um padrão.
Para parâmetros posicionais, a maneira de defini-los é óbvia, basta anexá-los ao comando, mas também existem maneiras de defini-los de outra maneira , além de alterar a lista desses parâmetros por meio do shiftcomando.
Em conclusão, o objetivo desses dois é diferente e existe por uma razão. Espero que as pessoas tenham entendido essa resposta e tenha sido divertido lê-la exatamente como escrevi essa resposta.
Nota sobre o comando set
O setcomando, de acordo com o manual, se comporta da seguinte maneira (do manual do bash, ênfase adicionada):
Sem opções, o nome e o valor de cada variável do shell são exibidos em um formato que pode ser reutilizado como entrada para definir ou redefinir as variáveis definidas no momento.
Em outras palavras, setanalisa variáveis específicas do shell, algumas das quais estão no ambiente, por exemplo HOME. Por outro lado, os comandos gostam enve printenvexaminam a variável de ambiente real com a qual um comando é executado. Veja também isso .
export 3transformar$3em uma variável de ambiente. Você não podeunset 3; e você não pode atribuir$3um novo valor usando3=val.