Há variáveis do shell como $0
, $1
, $2
, $?
, etc.
Tentei imprimir as variáveis de ambiente e shell usando o seguinte comando:
set
Mas essas variáveis não estavam na lista.
Então, basicamente, essas variáveis não são consideradas variáveis de shell / ambiente, certo? (mesmo que para produzi-las, você deve preceder com a $
, como você faz com variáveis de shell / ambiente)
export 3
transformar$3
em uma variável de ambiente. Você não podeunset 3
; e você não pode atribuir$3
um novo valor usando3=val
.Respostas:
Variáveis são uma das três variedades distintas de parâmetros no shell.
_
ou uma letra, seguida por zero ou mais letras, números ou_
.$1
,$2
...$0
, são todos vários caracteres de pontuação.set
exibe apenas as variáveis do shell.Um subconjunto das variáveis do shell são as variáveis de ambiente, cujos valores são herdados do ambiente quando o shell é inicializado ou são criados configurando o
export
atributo com um nome válido.fonte
set
exibe todos os parâmetros emzsh
(não $ 1, $ 2 ... mas $ *, $ @) e as funções em bash e bosh. Alguns shells, como o ksh93 e versões mais antigas dos envios de saída do traço, não foram mapeados para variáveis do shell. (env 1=foo ksh -c set
Imprimiria1=foo
)Variáveis de ambiente versus parâmetros posicionais
Antes de começarmos a discutir o
$INTEGER
tipo de variáveis, precisamos entender o que realmente são e como diferem das variáveis de ambiente. Variáveis como$INTEGER
os chamados parâmetros posicionais. Isso está descrito no padrão POSIX (Interface do sistema operacional portátil), seção 2.1 (ênfase minha):Por outro lado, variáveis como
$HOME
e$PATH
são variáveis de ambiente. Sua definição é descrita na seção 8 da norma :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 fizerecho 'Hello' 'World'
, ele imprimirá as seqüênciasHello
eWorld
, porque esses são parâmetros posicionais paraecho
as coisas nas quais você desejaecho
operar. Eecho
é 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 queHello
eWorld
é 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
HOME
ouPATH
possuem formato específico, significado específico e terão o mesmo significado para cada programa.HOME
A variável terá o mesmo significado para qualquer utilitário externo/usr/bin/find
ou 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 exemploUID
A 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-terminal
quando iniciado vai olhar para suaSHELL
variá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 paraksh
- o gnome-terminal irá aparecer emksh
vez debash
. Esse também é um exemplo de como o ambiente é usado pelos programas. Se eu disser explicitamentegnome-terminal
com-e
para 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
main
função C , que normalmente se parece com, onde
argc
está o número de argumentos da linha de comando eargv
é efetivamente um conjunto de parâmetros da linha de comando; depois, há umaenviron
função (no Linuxman -e 7 environ
) de acessar coisas como o caminho do diretório inicial do usuário, a lista de diretórios nosPATH
quais 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
,$2
e 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
bash
shell 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
-c
opção podem aproveitar$1
e$2
argumentos. Por exemplo,Observe que eu também usei
sh
lá, porque uma pequena peculiaridade da-c
opçã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
bash
com seus próprios parâmetros posicionais, mas esses parâmetros posicionais se tornaram parâmetros paraecho
estat
. E cada programa entende isso da sua maneira. Se dermosstat
uma stringHello World
e não houver arquivoHello World
, isso produzirá um erro;bash
trata-o apenas como uma sequência simples, masstat
espera que ela seja um nome de arquivo existente. Por outro lado, todos os programas concordariam que a variável de ambienteHOME
é 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:
Também podemos colocar variáveis no ambiente usando simplesmente
export variable=value
dentro do shell ou script. Ou podemos executar um comando com ambiente completamente vazio comenv -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
shift
comando.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
set
comando, de acordo com o manual, se comporta da seguinte maneira (do manual do bash, ênfase adicionada):Em outras palavras,
set
analisa variáveis específicas do shell, algumas das quais estão no ambiente, por exemploHOME
. Por outro lado, os comandos gostamenv
eprintenv
examinam a variável de ambiente real com a qual um comando é executado. Veja também isso .fonte
1="foo"
mas depois descobri que, por definição do POSIX, uma "palavra" (que é o nome de um objeto, como variável ou função) não pode ser iniciada com um dígito (veja uma pergunta que eu postei sobre o tópico ). Os parâmetros posicionais aparentemente são exceção a esta regra.$1
,$2
e assim por diante, no shell interativo e, de fato, isso é feito com oset
comando, geralmente para contornar a/bin/sh
limitação de não ter matrizes. Obrigado por trazer isso à minha atenção. Também vou editar a resposta nos próximos dias, pois ela precisa de um pouco de polimento extra e uma atualização.conda
, quando você executasource conda/bin/activate
, ele verifica se$1
,$2
etc., está definido, para determinar se foi executado como um script com argumentos ou não. Isso acaba sendo interrompido em sistemas que possuem aqueles configurados no ambiente interativo por algum motivo. Espero descobrir se esse comportamento não padrão é uma falha no sistema para definir essas variáveis no ambiente interativo ou no programa para usá-las para determinar se foi executado como um script.conda
desenvolvedores ou a quem é o autor original desse script, pois a verificação de${N}
parâmetros é definitivamente o caminho errado. Há perguntas sobre o mesmo tema aqui e aqui , e mais ou menos portátil maneira é verificar se${0}
é o mesmo que nome do script, enquanto quebash
na verdade tem variável de ambiente para o efeitoAs
$1, $2, $3, ..., ${10}, ${11}
variáveis são chamadas de parâmetros posicionais e são abordadas na seção manual do bash3.4.1
Quanto a ,
$?
e$0
esses parâmetros especiais são abordados na próxima seção3.4.2
fonte
$1
,$2
... são parâmetros posicionais , não são variáveis, muito menos variáveis de ambiente.Em Bourne-like terminologia concha,
$something
é chamado de parâmetro de expansão (também cobre${something#pattern}
e mais em alguns escudos como${array[x]}
,${param:offset}
,${x:|y}
e muitos operadores de expansão mais).Existem diferentes tipos de parâmetros:
$foo
,$PATH
$1
,$2
... os argumentos que seu script recebeu)$0
,$-
,$#
,$*
,$@
,$$
,$!
,$?
...os nomes de variáveis em shells semelhantes a Bourne devem começar com um caractere alfabético (qualquer um reconhecido pelo código do idioma ou limitado a a-zA-Z, dependendo do shell) e sublinhado e seguido por zero ou mais caracteres alfanuméricos ou sublinhados.
Dependendo do shell, as variáveis podem ter tipos diferentes (escalar, matriz, hash) ou receber determinados atributos (somente leitura, exportados, minúsculos ...).
Algumas dessas variáveis são criados pelo shell ou têm um significado especial para o shell (como
$OPTIND
,$IFS
,$_
...)As variáveis do shell que possuem o atributo export são automaticamente exportadas como variáveis de ambiente para os comandos que o shell executa.
Variável de ambiente é um conceito separado das variáveis do shell. Exportar uma variável de shell não é a única maneira de passar uma variável de ambiente para a execução de um comando.
passará uma
VAR
variável de ambiente para oprintenv
comando (que estamos dizendo para imprimir seu conteúdo), mas você também pode:ou:
por exemplo.
As variáveis de ambiente podem ter qualquer nome (podem conter qualquer caractere, mas
=
podem até estar vazias). Não é uma boa idéia atribuir um nome que não seja compatível com o nome de variável de shell semelhante a Bourne a uma variável de ambiente, mas é possível:Os shells mapearão as variáveis de ambiente que receberem para as variáveis do shell apenas para as variáveis de ambiente cujo nome são variáveis válidas do shell (e, em alguns shells, ignoram algumas especiais, como
$IFS
).Portanto, enquanto você poderia passar uma
1
variável de ambiente para um comando:Isso não significa que chamar um shell com essa variável de ambiente definiria o valor do
$1
parâmetro:fonte
Não, esses são parâmetros do script. Por exemplo, se você chamar seu script como:
então, dentro do script, haverá esses parâmetros disponíveis como
e $ 0 é o nome do próprio script.
Portanto, quando você está fora do script, essas variáveis não estão disponíveis (exceto $ 0, que exibe / bin / bash - o próprio shell).
fonte
$0
apontará para o processo atual do terminal (provavelmente bash) e$?
é simplesmente o código de saída do último processo.gnome-terminal
argumento com (gnome-terminal Hello World
). Eu pude ver$0
, mas não pude ver$1
e$2
.