Como exatamente “/ bin / [” funciona?

49

Sempre me surpreendo que na pasta /bin exista um programa [ .

É o que é chamado quando estamos fazendo algo como: if [ something ] ?

Ao chamar o programa [ explicitamente em um shell, ele solicita um ] correspondente e, quando forneço o colchete de fechamento, parece não fazer nada, não importa o que eu insira entre os colchetes.

É desnecessário dizer que a maneira usual de obter ajuda sobre um programa não funciona, ou seja, nem man [ nem [ --help funciona.

    
por Bregalad 11.01.2017 / 08:55

5 respostas

63

A tarefa do comando [ é avaliar expressões de teste. Ele retorna com um status de saída 0 (que significa verdadeiro ) quando a expressão é resolvida para true e outra coisa (o que significa false ) caso contrário.

Não é que não faça nada, é apenas que o resultado é encontrado no status de saída. Em um shell, você pode descobrir sobre o status de saída do último comando em $? para shells semelhantes a Bourne ou $status na maioria dos outros shells (fish / rc / es / csh / tcsh ...).

$ [ a = a ]
$ echo "$?"
0
$ [ a = b ]
$ echo "$?"
1

Em outros idiomas, como perl , o status de saída é retornado, por exemplo, no valor de retorno de system() :

$ perl -le 'print system("[", "a", "=", "a", "]")'
0

Observe que todos os shells modernos semelhantes a Bourne (e fish ) possuem um comando [ integrado. Aquele em /bin normalmente seria executado apenas quando você usa outro shell ou quando você faz coisas como env [ foo = bar ] ou find . -exec [ -f {} ] \; -print ou o comando perl acima ...

O comando [ também é conhecido pelo nome test . Quando chamado como test , não requer um argumento ] de fechamento.

Embora o seu sistema possa não ter uma página man para [ , ele provavelmente tem um para test . Mas, novamente, observe que isso documentaria a implementação /bin/[ ou /bin/test . Para saber sobre o [ embutido em seu shell, você deve ler a documentação do seu shell.

Para mais informações sobre o histórico desse utilitário e a diferença com a expressão de teste [[...]] ksh, convém dar uma olhada neste outro questionário Q & A aqui .

    
por 11.01.2017 / 11:09
41

I am always surprised that in the folder /bin there is a [ program.

Você está certo em se surpreender. Esse é um dos raros comandos POSIX, com o utilitário nulo ( : ), que não respeita a convenção de caracteres permitidos do arquivo de comandos (conjunto de caracteres de nome de arquivo portátil).

Is is what is called when we are doing something like: if [ something ]?

Precisamente, mas pode ser usado sem o if também.

By calling the [ program explicitly in a shell it asks for a corresponding ], and when I provide the closing bracket it seems to do nothing no matter what I insert between the brackets.

Não faz nada visível, mas na verdade faz exatamente o mesmo que quando usado com if , ou seja, define o status de saída como 0 (verdadeiro) ou qualquer outra coisa (falso) dependendo do que você coloca dentro dos colchetes. É (por um motivo) o mesmo comportamento que o comando test ; a única diferença é que ele procura o final ] . Veja man test para detalhes.

Needless to say, the usual way about getting help about a program does not work, i.e. neither man [ nor [ --help works.

Isso depende do seu sistema operacional. man [ definitivamente funciona para mim em algumas distribuições mainstream do Gnu / Linux, mas não no Solaris.

[ --help pode funcionar ou não dependendo da implementação, pois está quebrando a sintaxe de qualquer maneira, perdendo a finalização ] . Além disso, o padrão POSIX para o comando test / [ exclui explicitamente todas as opções, incluindo a terminação da opção -- , portanto, [ --help ] e test --help precisam retornar true e ficar em silêncio por design. Note que o que você coloca dentro dos colchetes ou depois de [ e que se parecem com opções (por exemplo, -f file , -n string e os gostos) não são opções mas operandos .

Todos os intérpretes de shell estilo Bourne modernos (como bash , ksh , dash e zsh para citar alguns) implementam o utilitário test / [ internamente como um arquivo interno, portanto, quando você os usa , a página de manual à direita para se referir pode ser a da shell, não a test one.

Antes do Unix System III (1981), o shell Bourne não implementava o utilitário test como um builtin, de modo que apenas a implementação do comando binário externo estava disponível. Não houve um comando [ (interno ou interno) até que o Unix System III, por exemplo, sob o Unix Versão 7, você tenha que digitar:

if test something ; then
…

em vez de:

if [ something ] ; then
…
    
por 11.01.2017 / 09:17
10

[ é, na verdade, mais conhecido como test . O uso típico desse comando é simplesmente avaliar expressões e retornar sua condição - verdadeiro ou falso. Ele é frequentemente usado em instruções if-then-else-fi , embora possa ser usado fora de instruções if para executar condicionalmente outros comandos por meio dos operadores && ou || do shell, assim.

$ [ -e /etc/passwd  ] && echo "File exists"
File exists

$ test -e /etc/passwd && echo "File exists"
File exists

Mais especificamente, a avaliação é comunicada a outros comandos através do status de saída. Alguns programas podem optar por emitir o status de saída para indicar diferentes tipos de eventos - o programa é concluído com êxito, ocorre um erro de tipo específico durante a execução ou erros de sintaxe. No caso do comando test , há 0 significa verdadeiro e 1 significa falso. Como Stephan apontou, erros de sintaxe produzem status de saída de 2 .

Sua localização depende do seu sistema e também explica por que você não viu a man page quando você fez man [ . Por exemplo, no FreeBSD está sob /bin . No Linux (ou no meu caso particular, Ubuntu 16.04) está em /usr/bin/ . Se você usar man [ ou man test em um sistema Linux, verá a mesma documentação aberta. Também é importante observar que seu shell pode ter sua própria implementação de test .

Deve-se notar também que este comando tem problemas , que a implementação do shell Korn (comumente conhecido como "expressão condicional" referência com colchetes duplos, [[ "$USER" = "root" ]] ) procura resolver. Esse recurso também é usado por outros shells, como bash e zsh .

    
por 11.01.2017 / 10:59
3

Neither man [ nor [ --help works

Em algumas distros (por exemplo, Ubuntu), man [ segue um link simbólico para test(1) . Em outros (por exemplo, Arch), esse não é o caso. (Mas a página test man também documenta o uso de [ )

type -a [ mostra que há um shell interno e um executável.

$ type -a [
[ is a shell builtin
[ is /usr/bin/[

bash-builtin [ --help apenas imprime uma mensagem de erro. (Mas como é um builtin, você pode usar help [ , ou olhar para a página man / docs do bash).

/usr/bin/[ --help imprime a saída de ajuda completa (para a versão GNU Coreutils), que começa com:

$ /usr/bin/[ --help
Usage: test EXPRESSION
  or:  test
  or:  [ EXPRESSION ]
  or:  [ ]
  or:  [ OPTION
Exit with the status determined by EXPRESSION.

      --help     display this help and exit
      --version  output version information and exit

e, em seguida, descreve a sintaxe permitida para EXPRESSÃO.

Essa é outra maneira de descobrir que [ e test são equivalentes.

BTW, se você estiver programando para bash (ou escrevendo one-liners interativamente), eu recomendaria [[ em vez de [ . É melhor de várias maneiras, veja os links na resposta de Serg.

    
por 11.01.2017 / 19:46
2
O comando

[ retorna status de saída zero se a expressão contida em seus argumentos for considerada verdadeira e status de saída diferente de zero se a expressão contida em seus argumentos for considerada falsa. Ele também falha com a mensagem de erro se seu último argumento não for ] (isso é feito apenas por razões estéticas).

Por exemplo:

[ hello ]
echo "Exit-status of [ hello ] is:" $?
[ abc = abc ]
echo "Exit-status of [ abc = abc ] is:" $?
[ ]
echo "Exit-status of [ ] is:" $?
[ abc = def ]
echo "Exit-status of [ abc = def ] is:" $?

… resultará:

Exit-status of [ hello ] is: 0      — because non-empty string is considered true
Exit-status of [ abc = abc ] is: 0  — because 'abc' really is same as 'abc'
Exit-status of [ ] is: 1            — because empty string is considered false
Exit-status of [ abc = def ] is: 1  — because 'abc' really differs from 'def'

No entanto, o bash e muitos outros shells realmente não invocam /bin/[ (ou /usr/bin/[ ) nesses casos, mas chame o comando interno com exatamente o mesmo comportamento (puramente por motivos de desempenho). Para invocar /bin/[ (não substituto interno do shell), você precisa especificar explicitamente seu caminho (por exemplo, /bin/[ hello ] ; não é necessário prefixar ] com o dirname embora ☺ ) ou para configurar o shell para não usar um substituto interno (por exemplo, enable -n [ no bash).

S .: Como foi dito em outras respostas, [ está relacionado a test . Mas test , ao contrário de [ , não exige ] como seu último argumento (e não espera nada disso; adicionar argumentos ] a test extras pode causar a falha mensagem de erro ou para retornar resultado errado) . O /bin/test e /bin/[ podem resolver para o mesmo arquivo (por exemplo, um é link simbólico ; neste caso o desvio de comportamento é provavelmente implementado por análise do comando atualmente chamado dentro do próprio código test / [ ) ou para arquivos diferentes. Para test , o shell também geralmente invoca o substituto interno, a menos que o caminho seja explicitamente especificado ( /bin/test ) ou esteja configurado para não fazer isso ( enable -n test ).

P. S .: Diferentemente de test e [ , o if moderno nunca é um arquivo real. Faz parte da sintaxe shell (por exemplo, bash): if commandA; then commandB; fi (novas linhas podem ser usadas em vez de ponto e vírgula) faz com que commandB seja executado se-e-somente-se commandA sair com status zero. Isso se encaixa perfeitamente no comportamento de test ou [ , permitindo combiná-los como if [ "$a" = foo ]; then …; fi (ou if test "$a" = foo; then …; fi - apenas menos legível) . No entanto, os scripts modernos geralmente usam [[ em vez de test ou [ , que (como if ) nunca é um arquivo real, mas sempre faz parte da sintaxe do shell.

P. P. S .: Quanto a man - nunca espere que man tenha um artigo em todos os comandos do seu sistema de arquivos. Informações sobre alguns (mesmo "reais", baseados em arquivo) comandos podem estar faltando, informações sobre alguns shell built-ins talvez presentes não apenas dentro de um artigo dedicado a shell específico (esse é o lugar onde você certamente encontrará informações sobre test , [ , if , [[ ). Ainda assim, muitas distribuições têm man -articles explícitos para test e [ . (Sobre --help , não é reconhecido com test por motivo óbvio: ele precisa lidar com casos como a=--help; test "$a" ; em algumas distribuições [ --help (sem fechar ] ) ainda mostra ajuda, em alguns não t.)

    
por 12.01.2017 / 11:48

Tags