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 / 526574
Accepted
Sergiy Kolodyazhnyy
Sergiy Kolodyazhnyy
Asked: 2019-06-25 01:10:32 +0800 CST2019-06-25 01:10:32 +0800 CST 2019-06-25 01:10:32 +0800 CST

Por que um grupo de comandos de chave precisa de espaços após a chave de abertura no POSIX Shell Grammar?

  • 772

TL; DR : Por que o grupo de chaves POSIX precisa de espaços após a {palavra reservada, mas o subshell não após a palavra reservada (?

A gramática do shell POSIX define o grupo de chaves e o subshell da seguinte maneira

brace_group      : Lbrace compound_list Rbrace

subshell         : '(' compound_list ')'

Agora, se estivermos lendo isso literalmente, os espaços são significativos. Isso significaria que deve haver espaço delimitando abertura e fechamento de chave e parênteses como em

{ echo hello world; }

( echo hello world )

Isso também se alinharia com as definições do Comando Composto :

Cada um desses comandos compostos tem uma palavra reservada ou operador de controle no início e uma palavra reservada ou operador de terminação correspondente no final.

No entanto, o que não faz sentido é porque (list)e ( list )funciona bem (esse espaço depois (não é necessário), no entanto, a expansão do brace tem que ter um espaço à esquerda, ou seja {echo hello;}, não funcionaria.

É claro que a palavra reservada sendo tratada como palavra shell faria sentido precisar de um espaço depois para se alinhar ao conceito de divisão de campo , no entanto, a própria definição não faz menção a espaços. Além disso, se {e (ambos são considerados palavras reservadas pela definição POSIX do comando composto, por que eles são tratados de maneira diferente em relação ao caractere de espaço após essas palavras reservadas? Agora, o manual do ksh(1) declara:

As palavras, que são sequências de caracteres, são delimitadas por caracteres de espaço em branco sem aspas (espaço, tabulação e nova linha) ou metacaracteres (<, >, |, ;, &, ( e ))

Em outras palavras, faz sentido que o ksh reconheça (como delimitador de palavras, onde a primeira palavra seria um comando ou atribuição de variável. POSIX, no entanto, não parece ser mencionado (como meta-caractere. A única explicação possível que encontrei no que diz respeito à gramática POSIX é que {é considerado um "token", onde as (não é listado como um.

/* These are reserved words, not operator tokens, and are
   recognized when reserved words are recognized. */


%token  Lbrace    Rbrace    Bang
/*      '{'       '}'       '!'   */

Então, qual seria o raciocínio preciso para essa discrepância?

Notas de resposta aceitas:

  • Movida a marca de seleção aceita para a resposta de Isaac, pois fornece uma citação do próprio padrão que aborda diretamente minha pergunta:

    Por exemplo, '(' e ')' são operadores de controle, de modo que não <space>é necessário em (lista). No entanto, '{' e '}' são palavras reservadas em { list;}, de modo que, neste caso, o e principal <space>e <semicolon>são obrigatórios.

  • Aceitando a resposta de Kusalananda . A resposta de Kusalananda atende ao que eu precisava, embora principalmente do ponto de vista informal e intuitivo; aponta {é uma palavra reservada e (é operador. Michael Homer também observou o mesmo nos comentários - que a definição do Comando Composto afirma (ênfase adicionada):

    Cada um desses comandos compostos tem uma palavra reservada ou operador de controle no início

  • {são definidos como palavras reservadas, semelhantes a forou while, listadas na Shell Grammar (veja o último bloco de código na pergunta)

  • A seção 2.9 declara (ênfase adicionada):

    Em particular, as representações incluem espaçamento entre tokens em alguns lugares onde <blank>s não seria necessário (quando um dos tokens é um operador).

  • Enquanto o padrão não define explicitamente (como um operador, (é referido como operador; especificamente, a seção 2.9.2 diz

    Se o pipeline começar com a palavra reservada ! e command1 é um comando de subshell, o aplicativo deve garantir que o operador ( no início de command1 seja separado do ! por um ou mais caracteres. O comportamento da palavra reservada ! imediatamente seguido pelo operador ( não é especificado.

  • A pergunta sobre o Stack Overflow por Digital Trauma aponta a Seção 2.4 sobre Palavras Reservadas:

    Este reconhecimento só ocorrerá quando nenhum dos caracteres for citado e quando a palavra for utilizada como:

    -A primeira palavra de um comando

  • Como mencionado na resposta de Kusalananda "Os espaços mostrados na gramática POSIX não são espaços que precisam estar lá nos dados de entrada do shell, mas apenas uma maneira de exibir a própria gramática. É o fato de as chaves serem palavras reservadas que implica que eles precisam ser cercados por espaços em branco" Como mencionado por Michael Homer nos comentários: "Se os espaços fossem significativos por si só, eles precisariam ser listados na produção "

Caso encerrado.

shell posix
  • 2 2 respostas
  • 1027 Views

2 respostas

  • Voted
  1. Kusalananda
    2019-06-25T01:23:21+08:002019-06-25T01:23:21+08:00

    A diferença entre as chaves e os parênteses é que as chaves (e !) são palavras reservadas, assim como for, if, thenetc. enquanto os parênteses são operadores de controle. As palavras precisam ser separadas por espaço em branco.

    Isso significa que assim como você não pode ter

    foriin*; do
    

    você não pode ter

    {somecommand;} >file
    

    ou

    if !somecommand; then
    

    Os espaços mostrados na gramática POSIX não são espaços que precisam estar nos dados de entrada do shell, mas apenas uma maneira de exibir a gramática em si. É o fato de que as chaves são palavras reservadas que implica que elas devem ser cercadas por espaços em branco, enquanto os parênteses de um subshell não.

    • 13
  2. Best Answer
    user232326
    2019-06-25T14:35:39+08:002019-06-25T14:35:39+08:00

    Essa é uma limitação da maneira como o shell quebra as linhas em tokens.

    O shell lê as linhas do arquivo de entrada e de acordo com a seção 2 "Introdução do Shell" as converte em uma palavra ou um operador :

    1. O shell divide a entrada em tokens: palavras e operadores

    { é uma palavra reservada

    Algumas palavras são palavras reservadas

    Palavras reservadas são palavras que têm um significado especial para o shell. As seguintes palavras serão reconhecidas como palavras reservadas:

    ! { } case do done elif else esac fi for if in then until while
    

    As palavras, para serem reconhecidas como palavras, devem ser delimitadas .

    As palavras reservadas são reconhecidas apenas quando são delimitadas ...

    Principalmente por espaços em branco (ponto 7) e por operadores.

    1. Se o caractere atual for um <blank> sem aspas, qualquer token contendo o caractere anterior é delimitado e o caractere atual deve ser descartado.

    (é um operador

    Os operadores ficam sozinhos :

    enquanto os próprios operadores são delimitadores.

    Onde "operadores" são :

    3.260 Operador

    Na linguagem de comando do shell, um operador de controle ou um operador de redirecionamento .

    Os operadores de redirecionamento são :

    Operador de redirecionamento

    Na linguagem de comando shell, um token que executa uma função de redirecionamento. É um dos seguintes símbolos:

    <     >     >|     <<     >>     <&     >&     <<-     <>
    

    Os operadores de controle são :

    3.113 Operador de Controle

    Na linguagem de comando shell, um token que executa uma função de controle. É um dos seguintes símbolos:

    &   &&   (   )   ;   ;;   newline   |   ||
    

    Conclusão

    Assim, '(' e ')' são operadores de controle enquanto '{' '}' são palavras reservadas.

    E a mesma descrição exata da sua pergunta está dentro da especificação :

    Por exemplo, '(' e ')' são operadores de controle, de modo que nenhum <espaço> é necessário em (lista). No entanto, '{' e '}' são palavras reservadas em { list;}, de modo que, neste caso, o <espaço> e o <ponto e vírgula> iniciais são obrigatórios.

    O que explica exatamente por que um espaço (ou algum outro delimitador) é necessário após um {.

    Isso é válido:

    { echo yes;}
    

    Como é este:

    {(echo yes);}
    

    Este:

    {(echo yes)}
    

    Ou mesmo isso:

    {>/dev/tty echo yes;}
    
    • 7

relate perguntas

  • Como funciona este comando? mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc -l 1234 > /tmp/f

  • FreeBSD's sh: funções de lista

  • Existe uma maneira de fazer ls mostrar arquivos ocultos apenas para determinados diretórios?

  • o que grep -v grep faz

  • Como salvar um caminho com ~ em uma variável?

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