Por que o condicional não funciona quando eu o uso diretamente sem uma variável?

5

Isso me dá um erro que diz muitos argumentos:

if [ $( file -b $i ) == "directory" ]

Mas quando eu tentei isso

name=$( file -b $i )
if [ name == "directory" ]

Parece funcionar bem.

Alguém pode explicar isso ou apontar nos documentos uma explicação? Eu sou novo no bash, mas do ponto de vista de outras linguagens de programação, isso não faz sentido.

    
por Script Kitty 15.01.2017 / 04:17

3 respostas

7

Alguns problemas:

  • ] indica o final dos argumentos para [ ( test ) e deve ser o último argumento; você tem um par de ] s, o que está errado; presumivelmente você pretendia usar:

    if [ $( file -b $i ) == "directory" ]
    
  • Se você tivesse usado o acima, obteria bash: [: too many arguments , porque a divisão de palavras seria feita na saída da expansão de variável ( $i ) e, em seguida, a substituição de comando, $() ( file command ) e [ verá várias palavras antes de = , levando à mensagem de erro. Você precisa citar a expansão da variável e a substituição de comandos:

    [ "$(file -b "$1")" == "directory" ]
    

Como observação, você deve usar o bash keyword [[ , em vez de [ , pois o primeiro lidará com a divisão de palavras (e a expansão do nome do caminho) para você.

    
por 15.01.2017 / 04:26
4
if [ $( file -b $i ) == "directory" ]

Duas questões aqui:

  • Use = único para comparação de string. Veja man test para a sintaxe apropriada (observe que [ em muitos casos tem implementação específica do shell, portanto, consulte o man page do seu shell se você não tiver a documentação para test ). Se você realmente precisar de == , use [[ , que é característica de muitos shells parecidos com bourne, incluindo bash, ksh, zsh. NOTA: enquanto == existe no bash desde a versão 2.0 , "= deve ser usado com o comando test para POSIX conformidade ". ( página do bash man ).

  • Cite todas as suas variáveis como "$()" . Especificamente de interesse é $i . Nomes de arquivos com espaço quebrarão $i em várias palavras devido à expansão de palavras da shell.

Exemplo:

bash-4.3$ mkdir with\ space
bash-4.3$ i="./with space"
bash-4.3$ set -x
bash-4.3$ [ $( file -b $i ) == "directory" ] && echo "YES"
++ file -b ./with space
+ '[' cannot open ''./with'\''' '(No' such file or 'directory)' cannot open ''space'\''' '(No' such file or 'directory)' == directory ']'
bash: [: too many arguments
name=$( file -b $i )
if [ name == "directory" ]

Problemas aqui:

  • name não é expandido para variável, é apenas uma string "nome" aqui. Você precisa de "$name" e novamente, único =

Além disso, ele não pode ter funcionado, já que o status de saída de test é retornado como falso (status de saída 1)

$ name=$(file -b /etc)
$ set -x
$ [ name == "directory" ]
+ '[' name '==' directory ']'
$ echo $?
+ echo 1
1

O acima foi testado em bash e mksh shells.

    
por 15.01.2017 / 04:26
4

Existem muitos problemas! Vamos pegar essa parte que está "funcionando":

 name=$( file -b $i )
 if [ name == "directory" ]

Isso atribui a saída do comando file à variável chamada name , mas não a usa; em vez disso, ele executa o comando [ com 3 parâmetros: name , == e directory . Aceitar == é uma extensão bash.

Se isso for corrigido para usar $name em vez de name , você obterá novamente um problema de too many arguments em muitos casos. Isso ocorre porque file retorna vários resultados de palavras como ASCII text . Então, depois que o comando é executado, você obtém

if [ ASCII text == directory ]

e agora é óbvio que falta algum agrupamento ao comando.

if [ "$(file -b -- "$i")" = "directory" ]

é provavelmente o que você quer: = em vez de == para portabilidade, e citando o resultado da substituição de comando que você quase sempre quer fazer .

    
por 15.01.2017 / 06:14