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 / 432660
Accepted
siery
siery
Asked: 2018-03-22 11:21:00 +0800 CST2018-03-22 11:21:00 +0800 CST 2018-03-22 11:21:00 +0800 CST

Correspondência de números com regex na instrução case

  • 772

Eu quero verificar se um argumento para um script de shell é um número inteiro (ou seja, um número inteiro não negativo: 0, 1, 2, 3, …, 17, …, 42, …, etc, mas não 3,1416 ou −5 ) expresso em decimal (portanto, nada como 0x11 ou 0x2A). Como posso escrever uma instrução de caso usando regex como condição (para corresponder a números)? Eu tentei algumas maneiras diferentes que encontrei (por exemplo, [0-9]+ou ^[0-9][0-9]*$); nenhum deles funciona. Como no exemplo a seguir, os números válidos estão caindo no regex numérico que deve capturá-los e correspondem ao  *curinga.

i=1
let arg_n=$#+1

while (( $i < $arg_n )); do
    case ${!i} in
    [0-9]+)
        n=${!i}
        ;;
    *)
        echo 'Invalid argument!'
        ;;
    esac
    let i=$i+1
done

Resultado:

$ ./cmd.sh 64
Invalid argument!
bash regular-expression
  • 3 3 respostas
  • 18728 Views

3 respostas

  • Voted
  1. Best Answer
    glenn jackman
    2018-03-22T11:41:06+08:002018-03-22T11:41:06+08:00

    casenão usa regexes, usa padrões

    Para "1 ou mais dígitos", faça o seguinte:

    shopt -s extglob
    ...
        case ${!i} in
            +([[:digit:]]) )
                n=${!i}
                ;;
        ...
    

    Se você quiser usar expressões regulares, use o =~operador dentro[[...]]

    if [[ ${!i} =~ ^[[:digit:]]+$ ]]; then
        n=${!i}
    else
        echo "Invalid"
    fi
    
    • 11
  2. G-Man Says 'Reinstate Monica'
    2018-03-22T21:09:37+08:002018-03-22T21:09:37+08:00

    Como diz glenn , “ casenão usa regexes, usa padrões ”. Como bash(1) diz,

    case word in [ [(] pattern [ | pattern ] ... ) list ;; ] ... esac

          Um casecomando primeiro expande worde tenta combiná-lo com cada um pattern, usando as mesmas regras de correspondência da expansão do nome do caminho (consulte Expansão do nome do caminho abaixo).

    Da mesma forma, a especificação POSIX diz,

    … cada padrão … deve ser comparado com a expansão da palavra , de acordo com as regras descritas em Notação de Correspondência de Padrões  …

    Portanto, os padrões são padrões de expansão de nome de caminho, também conhecidos como curingas, também conhecidos como globs, como em ls -l -- *.shou rm -- *.bak.

    Claro, shopt -s extglobe [[ … =~ … ]] são a coisa mais legal desde o pão fatiado, mas não são POSIX e pode ser útil saber como usar as ferramentas originais. Durante anos, os programadores verificaram, por exemplo, se uma string era um número verificando se não era um número. Você definiu um número como uma string que consiste (totalmente) em um ou mais dígitos. Portanto, uma string não é um número se for nula ou se contiver um caractere que não seja um dígito. Podemos testar essas condições com uma casedeclaração como segue:

    case "$1" in
        ("")
            # null
               ︙
            ;;
        (*[!0-9]*)
            # contains non-numeric character(s)
               ︙
            ;;
        (*)
            # is a whole number (non-negative integer)
               ︙
    esac
    

    onde [!0-9]é a velha maneira de dizer [^0-9], que, é claro, significa qualquer caractere que não seja um dígito. ( [!…]e [^…]ambos funcionam em bash.  [!…]é necessário para funcionar com POSIX; o ​​resultado de [^…]não é especificado.) Se você não se importa com o tipo de não número de uma string, pode combinar os padrões não numéricos:

    case "$1" in
        ("" | *[!0-9]*)
            # not a number
               ︙
            ;;
        (*)
            # is a number
               ︙
    esac
    

    Como exercício, aqui está uma caseinstrução para lidar com qualquer tipo de número real — para ser mais preciso, uma string de um ou mais dígitos, opcionalmente com um ponto ( .) em algum lugar e, opcionalmente, um sinal de menos ( -) no início.

    case "$1" in
        (*[!-.0-9]*)
            # contains non-numeric character(s)
            ;;
        (*?-*)
            # contains '-' somewhere other than the first position
            ;;
        (*.*.*)
            # contains multiple decimal points
            ;;
        (*)
            case "$1" in
                (*[0-9]*)
                    # is a real number
                    ;;
                (*)
                    # not a number
            esac
    esac
    

    Eu adicionei o case-within-a- casepara verificar se a string contém, de fato, pelo menos um dígito. Isso não foi necessário no exemplo inteiro porque testei se a string era nula; um teste que removi desta declaração. Sem o segundo case, um único -ou um único .— ou mesmo -.— se qualificaria como um número. Claro que poderíamos adicionar padrões para lidar com essas exceções, mas isso pode se tornar complexo. (Por exemplo, quase postei esta resposta sem perceber que -.era uma das exceções.) Acredito que a abordagem acima é mais flexível e robusta.

    É claro que os padrões não numéricos também podem ser combinados aqui: (*[!-.0-9]* | *?-* | *.*.*).

    • 3
  3. Stéphane Chazelas
    2018-03-22T23:30:30+08:002018-03-22T23:30:30+08:00

    Para combinar números com regexp em casedeclarações , você precisa de um shell cujos curingas suportem regexps. Eu só sei de ksh93 com aqueles.

    Com globs ksh93, você pode fazer ~(E)^[0-9]+$ou ~(E:^[0-9]+$)usar um Eregexp xtended em um padrão glob ou ~(P)^\d+$usar um regexp semelhante a perl (também Gpara regexp básico, Xpara regexp aumentada, Vpara regexp SysV).

    Então:

    #! /bin/ksh93 -
    for i do
      case $i in
        (~(E)^[0-9]+$)
          n=$i;;
        (*)
          echo >&2 'Invalid argument!'
          usage
      esac
    done
    
    • 1

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

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

    • 4 respostas
  • Marko Smith

    ssh Não é possível negociar: "nenhuma cifra correspondente encontrada", está rejeitando o cbc

    • 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

    Como descarregar o módulo do kernel 'nvidia-drm'?

    • 13 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
    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
    Wong Jia Hau ssh-add retorna com: "Erro ao conectar ao agente: nenhum arquivo ou diretório" 2018-08-24 23:28:13 +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
  • Martin Hope
    Bagas Sanjaya Por que o Linux usa LF como caractere de nova linha? 2017-12-20 05:48:21 +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