Em V7 Unix - onde o shell Bourne fez sua estreia - [ foi chamado test , e existia apenas como /bin/test . Então, codifique você escreveria hoje como:
if [ "$foo" = "bar" ] ; then ...
você teria escrito como
if test "$foo" = "bar" ; then ...
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 que if usa para decidir o que fazer em seguida. Esse comando pode ser construído no shell ou pode ser um programa externo.¹
[ como uma alternativa para test veio mais tarde.² Pode ser um sinônimo interno para test , mas também é fornecido como /bin/[ em sistemas modernos para shells que não o possuem como um .
[ e test podem ser implementados usando o mesmo código. Este é o caso de /bin/[ e /bin/test no OS X, onde estes são links físicos para o mesmo executável. ³ Como resultado, a implementação ignora completamente o ] à direita: ele não é necessário se você o chamar como /bin/[ e não reclama se fizer fornecer /bin/test .⁴
Nenhum desse histórico afeta [[ , porque nunca houve um programa primordial chamado [[ . Existe apenas dentro desses shells que o implementam como uma extensão do shell POSIX .
Parte da distinção entre "construído" e "palavra-chave" se deve a esse histórico. Isso também reflete o fato de que as regras de sintaxe para analisar [[ expressões são diferentes, conforme indicado na resposta de John1024 .⁵
Notas de rodapé:
-
Quando você olha dessa maneira, fica claro por que você deve colocar espaços em torno de [ em scripts de shell, ao contrário do modo como parênteses e colchetes funcionam na maioria das outras linguagens de programação. Se o analisador de comandos do shell permitisse if["$x"... , ele também teria que permitir iftest"$x"...
-
Aconteceu por volta de 1980. /bin/[ não existe na minha cópia do Antigo Unix V7 de 1979, nem o man test o documenta como um alias. Na entrada da página man correspondente, eu tenho em uma cópia de pré-lançamento do Manual do Sistema III de 1980, é listado.
-
ls -i /bin/[ /bin/test
-
Mas não conte com esse comportamento. A versão interna do Bash de [ exige o fechamento de ] , e sua implementação test integrada irá reclamar se você fizer fornecê-la.
-
A distinção entre comandos externos e internos também pode ser importante por outro motivo: as duas implementações podem se comportar de maneira diferente. Este é o caso de echo em muitos sistemas. Como há apenas uma implementação, essa distinção não precisa ser feita para uma palavra-chave.