AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 741645
Accepted
Weijun Zhou
Weijun Zhou
Asked: 2023-04-01 16:53:49 +0800 CST2023-04-01 16:53:49 +0800 CST 2023-04-01 16:53:49 +0800 CST

Por que os espaços não são necessários em torno de alguns operadores de comparação de strings em expressões condicionais no bash?

  • 772

Achei algo surpreendente quando estou escrevendo para algum script bash hoje. Eu o fixei neste exemplo mínimo.

[[ a>b ]]; echo $?

Com base no meu entendimento, como não há espaços ao redor do >, isso deve testar se a string a>bnão está vazia e deve retornar um código de erro de 0. No entanto, o comando acima ecoa 1em ambas as versões do bash que testei (detalhes abaixo).

Eu também testei usando o antigo testcomando "good",

[ a>b ]; echo $?echos 0(testa se a string anão está vazia e cria um arquivo vazio bno meu diretório de trabalho atual, aparentemente >bé tratado como um redirecionamento, o que é compreensível).

Então eu tentei mais algumas outras coisas

  • [[ b>a ]]; echo $?ecos 0e nenhum arquivo é criado.
  • [[ b<a ]]; echo $?ecos 1e nenhum arquivo é criado.
  • [[ a<b ]]; echo $?ecos 0e nenhum arquivo é criado.
  • [ b>a ]; echo $?echos 0e cria um arquivo vazio a.
  • [ b<a ]; echo $?relata um erro de arquivo ausente ae ecos 1devido a esse erro.
  • [ a<b ]; echo $?relata um erro de arquivo ausente be ecos 1devido a esse erro.
  • [[ a=b ]]; echo $?echos 0porque está testando se a string a=bnão está vazia como eu esperava.
  • [ a=b ]; echo $?ecos 0pelo mesmo motivo.
  • [[ a==b ]]; echo $?ecos 0pelo mesmo motivo.
  • [ a==b ]; echo $?ecos 0pelo mesmo motivo.
  • [[ a!=a ]]; echo $?e [ a!=a ]; echo $?ambos ecoam 0(esperado)

Portanto, parece que apenas os espaços ao redor de <e >podem ser omitidos em uma expressão condicional, mas não =ou ==ou !=se a intenção for fazer comparação de strings. Mas por que ele é projetado dessa maneira? Também pode ser minha omissão, mas isso não parece estar documentado em nenhum lugar do manual do bash.

Meu problema original é tentar usar >sem escape como parte de um padrão em uma expressão condicional ( [[ ... ]]). Originalmente, pensei que, desde que não envolvesse o >com espaços, poderia usá-lo sem escape sem problemas, porque não faz sentido (e acaba sendo impossível após alguns testes) fazer redirecionamentos dentro de um condicional expressão também.

No entanto, verifica-se que não é o caso. É claro que a solução simples é apenas escapar disso >e escrever \>, mas não entendo por que isso é necessário.

Aqui estão as versões do bash que usei para testar,

GNU bash, version 5.2.2(1)-release (aarch64-unknown-linux-android)

e

GNU bash, version 3.2.25(1)-release (x86_64-redhat-linux-gnu)

Meus experimentos são realizados sob env -i bash --norc --noprofile.

bash
  • 1 1 respostas
  • 713 Views

1 respostas

  • Voted
  1. Best Answer
    Stéphane Chazelas
    2023-04-01T17:05:32+08:002023-04-01T17:05:32+08:00

    Isso se resume ao fato de que caracteres como &, ;, (, |, <, >, tab são metacaracteres na sintaxe do shell. Eles formam seus próprios tokens (ou podem se combinar em mais tokens como ;;, |&, ||...). Isso é diferente de caracteres como [, {, !¹, -e =que são semelhantes a letras² e números neste.

    Dentro da [[...]]construção do shell Korn, o shell entende uma microlinguagem separada, mas segue aproximadamente as mesmas regras de tokenização do lado de fora.

    Pela mesma razão, fora de [[...]], você pode fazer:

    (echo a>file|tr a b&)
    

    e não precisa escrever:

    ( echo a > file | tr a b & )
    

    Ou mesmo coisas como if((1))then<file&&(uname)fi.

    Aqui você pode fazer:

    [[(a>b||b<d)]]
    

    como (, e são metacaracteres de shell >.|)

    Os metacaracteres devem ser citados (seja com '...', "...", \, $'...'...) para serem interpretados literalmente.

    [[x]]não funcionaria porque o shell vê apenas um [[x]]token. E a [[palavra-chave para iniciar essa [[...]]construção nem seria reconhecida. [[ a==b ]]não é o mesmo que [[ a == b ]], como na [[...]]microlinguagem, a==bé um único token, então isso é interpretado da mesma forma que [[ -n 'a==b' ]].

    [em si é apenas um comando normal, por isso é analisado da mesma forma que outro comando.

    [ a>b ]
    

    é executado [com ae ]como argumento e sua saída é redirecionada para b, mesmo que [ a ] > b, assim como echo a>b ]é igual a echo a ] > bou >b echo a ].

    Observe que é diferente por dentro ((...))(também do ksh), que também vem com sua própria microlinguagem semelhante a C, mas desta vez as regras de tokenização são diferentes. Por exemplo, você pode escrever ((var=123+1))ou ((a==b))e não precisa ((var = 123 + 1))de ou ((a == b)).


    ¹ {está envolvido na expansão de colchetes e também é uma palavra reservada do shell, mas processada após a tokenização, embora [esteja envolvida na tokenização ao analisar atribuições. a[1 + 1]=fooem bash ou ksh (não zsh) é analisado como uma palavra de atribuição, não como execução a[1com +e 1]=foocomo argumentos. !é uma palavra reservada como {, mas também está envolvida na expansão do histórico, embora seja apenas para invocações interativas do shell.

    ² observe que as letras e -estão envolvidas em alguns dos [[...]]operadores, como -nt, -eq, -lt...

    • 17

relate perguntas

  • exportar variáveis ​​​​env programaticamente, via stdout do comando [duplicado]

  • Problema estranho ao passar variáveis ​​do arquivo de texto

  • Enquanto a linha lê mantendo os espaços de escape?

  • ordem de substituição de processos `te` e `bash`

  • Execute um script muito lento até que seja bem-sucedido

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Possível firmware ausente /lib/firmware/i915/* para o módulo i915

    • 3 respostas
  • Marko Smith

    Falha ao buscar o repositório de backports jessie

    • 4 respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    user12345 Falha ao buscar o repositório de backports jessie 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl Por que a maioria dos exemplos do systemd contém WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve