Tanto quanto eu sei, [[
é uma versão aprimorada do [
, mas estou confuso quando vejo [[
como uma palavra-chave e [
sendo mostrado como um interno.
[root@server ~]# type [
[ is a shell builtin
[root@server ~]# type [[
[[ is a shell keyword
TLDP diz
Um interno pode ser sinônimo de um comando do sistema com o mesmo nome, mas o Bash o reimplementa internamente. Por exemplo, o comando Bash echo não é o mesmo que / bin / echo, embora o comportamento deles seja quase idêntico.
e
Uma palavra-chave é uma palavra reservada, token ou operador. Palavras-chave têm um significado especial para o shell e, de fato, são os blocos de construção da sintaxe do shell. Como exemplos, por enquanto, faça e! são palavras-chave. Semelhante a um builtin, uma palavra-chave é codificada no Bash, mas ao contrário de um builtin, uma palavra-chave não é em si um comando, mas uma subunidade de uma construção de comando. [2]
Isso não deveria fazer tanto [
e [[
uma palavra-chave? Falta alguma coisa aqui? Além disso, esse link reafirma que ambos [
e [[
devem pertencer ao mesmo tipo.
fonte
if "[" $x -eq 3 ]
funciona como esperado (porque Bash procura o comando chamado[
, e este existe), masif "[[" $x -eq 3 ]]
não não funciona (porque mais uma vez Bash procura por um comando do nome apropriado, mas não há[[
comando)./usr/bin/echo
, mas isso não significa que não seja um builtin .Respostas:
A diferença entre
[
e[[
é bastante fundamental.[
é um comando. Seus argumentos são processados da mesma maneira que qualquer outro argumento de comando. Por exemplo, considere:O shell expandirá
$name
e executará a divisão de palavras e a geração de nome de arquivo no resultado, da mesma forma que faria com qualquer outro comando.Como exemplo, o seguinte falhará:
Para que este funcione corretamente, são necessárias aspas:
[[
é uma palavra-chave shell e seus argumentos são processados de acordo com regras especiais. Por exemplo, considere:O shell irá expandir
$name
, mas, ao contrário de qualquer outro comando, ele irá executar nem repartição de palavras nem geração de nome de arquivo no resultado. Por exemplo, o seguinte será bem-sucedido, apesar dos espaços incorporadosname
:Sumário
[
é um comando e está sujeito às mesmas regras que todos os outros comandos que o shell executa.Como
[[
é uma palavra-chave, não um comando, no entanto, o shell a trata especialmente e opera sob regras muito diferentes.fonte
man bash
. Consulte, em particular, as seções intituladas "EXPANSÃO SIMPLES DE COMANDO" e "EXECUÇÃO DE COMANDO". Além[[
, outros festança palavras-chave incluemif
,then
,while
, e 'caso'. Não há regras gerais para palavras-chave: cada palavra-chave é um caso especial.man bash
inclui detalhes para cada um.No V7 Unix - onde o shell Bourne fez sua estréia -
[
foi chamadotest
, e existia apenas como/bin/test
. Então, código que você escreveria hoje como:você teria escrito como
Esta segunda notação ainda existe, e eu acho que é mais claro sobre o que está acontecendo: você está chamando um comando chamado
test
, que avalia seus argumentos e retorna um código de status de saída queif
usa para decidir o que fazer a seguir. Esse comando pode ser incorporado ao shell ou pode ser um programa externo.¹[
como uma alternativa quetest
veio mais tarde.² Pode ser um sinônimo interno paratest
, mas também é fornecido como/bin/[
em sistemas modernos para shells que não o possuem como interno.[
etest
pode ser implementado usando o mesmo código. Este é o caso para/bin/[
e/bin/test
no OS X, onde esses são links físicos para o mesmo executável.³ Como resultado, a implementação ignora completamente a trilha]
: não é necessária se você chamar assim/bin/[
e não se queixar se fazer fornecê-lo a/bin/test
.⁴Nada dessa história afeta
[[
, porque nunca houve um programa primordial chamado[[
. Existe puramente dentro dos shells que o implementam como uma extensão do shell POSIX .Parte da distinção entre "embutido" e "palavra-chave" se deve a esse histórico. Também reflete o fato de que as regras de sintaxe para analisar
[[
expressões são diferentes, como apontado na resposta de John1024.Notas de rodapé:
Quando você olha dessa maneira, fica claro por que você deve colocar espaços
[
nos scripts de shell, diferente da maneira como parênteses e colchetes funcionam na maioria das outras linguagens de programação. Se o analisador de comandos do shell permitisseif["$x"...
, ele também teria que permitiriftest"$x"...
Isso aconteceu por volta de 1980.
/bin/[
não existe na minha cópia do Ancient Unix V7 de 1979, nem aman test
documenta como um pseudônimo. Na entrada da página de manual correspondente que eu tenho em uma cópia de pré-lançamento do manual do System III de 1980, ela está listada.ls -i /bin/[ /bin/test
Mas não conte com esse comportamento. A versão Bash built-in de
[
requer o fechamento]
, e sua built-intest
aplicação vai reclamar se você não fornecê-la.A distinção de comando interno x externo também pode ser importante por outro motivo: as duas implementações podem se comportar de maneira diferente. Este é o caso
echo
em muitos sistemas. Como existe apenas uma implementação, essa distinção precisa ser feita para uma palavra-chave.fonte
builtin
ekeyword
entre[
e[[
quando as duas oferecem a mesma funcionalidade (exceto pelo fato de que ela[[
vem com mais recursos[
)?[[
Sendo @sree uma palavra-chave, o bash pode fazer coisas que não são possíveis[
- por exemplo, citar não é necessário muito tempo, porque o shell está ciente de que é uma variável. Ou seja, o processamento da linha de comando é afetado quando uma palavra-chave é usada, mas não quando um interno é usado - isso acontece muito mais tarde.[
built-in, mas o código está comentado.cd
é um builtin, mas não oculta nada (cd
não pode ser implementado como um programa externo).[[
uma palavra-chave permite que o shell use regras de análise especiais para seus argumentos. Assim, infelizmente, meu voto inicial vai para John1024.[
era originalmente apenas um comando externo, outro nome para/bin/test
. Mas alguns comandos, como[
eecho
, são usados com tanta frequência em scripts de shell que os implementadores de shell decidiram copiar o código diretamente no próprio shell, em vez de precisar executar outro processo toda vez que forem usados. Isso transformou esses comandos em "builtins", embora você ainda possa invocar o programa externo por todo o caminho.[[
veio muito mais tarde. Embora o builtin seja implementado internamente no shell, ele é analisado como comandos externos. Conforme explicado na resposta de John1024, isso significa que variáveis não citadas receberão a divisão de palavras e tokens como>
e<
são processados como redirecionamento de E / S. Isso tornou inconveniente escrever expressões complexas de comparação.[[
foi criado como sintaxe do shell, para que pudesse ser analisado ideosincraticamente. Dentro de[[
variáveis, não é possível dividir palavras,<
e>
pode ser usado como operadores de comparação,=
pode se comportar de maneira diferente, dependendo se o próximo parâmetro é citado ou não, etc. Essas são todas as conveniências que tornam[[
mais fácil o uso do que o[
comando / builtin tradicional .Eles não podiam simplesmente recodificar
[
como sintaxe como essa, porque teria sido uma alteração incompatível em milhões de scripts. Ao usar a nova[[
sintaxe, que não existia anteriormente, eles poderiam renovar totalmente a maneira como é usada de uma maneira compatível para cima.Isso é semelhante à evolução que resultou em
$((...))
sintaxe para expressões aritméticas, que substituíram principalmente oexpr
comando tradicional .fonte
O mais recente
[[
embash
uma otimização de[
.O clássico
[
tem uma grande desvantagem, quando é usado com freqüência para fazer uma operação trivial: ele gera um novo processo toda vez:(cria um novo espaço de endereço apenas para comparação
0
e1
! Toda vez!)Eu acho que um ponto principal da adição
[[
foi tornar a avaliação da expressão interna[
não gerar um processo extra. Mas como o[
trabalho não pode ser alterado - isso criaria muita confusão e problemas. Portanto, a otimização foi implementada com um novo nome, de forma mais eficiente, a saber, um comando embutido no shell.Tornou-se palavra-chave na sintaxe do shell como efeito colateral.
No momento em que
[
foi usado primeiro, era o caminho certo para fazê-lo com um processo externo.fonte
[
originalmente fosse um comando externo, ele foi adicionado ao shell bastante cedo, provavelmente no momento em que o Unix System III foi lançado e definitivamente antes do lançamento do Unix System V. Portanto, o 'processo extra' não é um problema há muito tempo. No entanto, a sintaxe permaneceu inalterada - foi tratada como se fosse um comando externo.[
é ao mesmo tempo - o que significa algumas mudanças ...