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 / 553022
Accepted
Harold Fischer
Harold Fischer
Asked: 2019-11-20 12:43:04 +0800 CST2019-11-20 12:43:04 +0800 CST 2019-11-20 12:43:04 +0800 CST

Como posso ter certeza de que uma string contém pelo menos uma letra maiúscula, uma letra minúscula, um número e um caractere de pontuação?

  • 772

Isto é o que estou usando agora para fazer o trabalho:

#!/bin/sh --

string='Aa1!z'

if ! printf '%s\n' "$string" | LC_ALL=C grep -q '[[:upper:]]' || \
   ! printf '%s\n' "$string" | LC_ALL=C grep -q '[[:lower:]]' || \
   ! printf '%s\n' "$string" | LC_ALL=C grep -q '[[:digit:]]' || \
   ! printf '%s\n' "$string" | LC_ALL=C grep -q '[[:punct:]]'; then
  printf '%s\n' 'String does not meet your requirements'
else
  printf '%s\n' 'String meets your requirements'
fi

Isso é extremamente ineficiente e verboso. Existe uma maneira melhor de fazer isso?

shell
  • 9 9 respostas
  • 4961 Views

9 respostas

  • Voted
  1. RomanPerekhrest
    2019-11-20T12:56:52+08:002019-11-20T12:56:52+08:00

    awkCom correspondência de padrões flexível :

    if [[ $(echo "$string" | awk '/[a-z]/ && /[A-Z]/ && /[0-9]/ && /[[:punct:]]/') ]]; then  
        echo "String meets your requirements"
    else 
        echo "String does not meet your requirements"
    fi
    
    • 7
  2. Best Answer
    Stéphane Chazelas
    2019-11-20T14:24:25+08:002019-11-20T14:24:25+08:00

    Com uma chamada para awke sem pipe:

    #! /bin/sh -
    string='whatever'
    
    has_char_of_each_class() {
      LC_ALL=C awk -- '
        BEGIN {
          for (i = 2; i < ARGC; i++)
            if (ARGV[1] !~ "[[:" ARGV[i] ":]]") exit 1
        }' "$@"
    }
    
    if has_char_of_each_class "$string" lower upper digit punct; then
      echo OK
    else
      echo not OK
    fi
    

    Isso é POSIX, mas observe que mawkainda não suporta classes de caracteres POSIX. O --não é necessário com s compatíveis com POSIX awk, mas seria em versões mais antigas do busybox awk(o que bloquearia os valores $string que começam com -).

    Uma variante dessa função usando uma caseconstrução de shell:

    has_char_of_each_class() {
      input=$1; shift
      for class do
        case $input in
          (*[[:$class:]]*) ;;
          (*) return 1;;
        esac
      done
    }
    

    Observe, no entanto, que alterar a localidade para o shell no meio de um script não funciona com todas as shimplementações (portanto, você precisaria que o script já fosse chamado na localidade C se desejar que a entrada seja considerada como codificada em o conjunto de caracteres de localidade C e as classes de caracteres para corresponder apenas aos especificados por POSIX).

    • 7
  3. Kusalananda
    2019-11-20T13:57:33+08:002019-11-20T13:57:33+08:00

    O script a seguir é mais longo que seu código, mas mostra como você pode testar uma string em uma lista de padrões. O código detecta se a string corresponde a todos os padrões ou não e imprime um resultado.

    #!/bin/sh
    
    string=TestString1
    
    failed=false
    
    for pattern in '*[[:upper:]]*' '*[[:lower:]]*' '*[[:digit:]]*' '*[[:punct:]]*'
    do
        case $string in
            $pattern) ;;
            *)
                failed=true
                break
        esac
    done
    
    if "$failed"; then
        printf '"%s" does not meet the requirements\n' "$string"
    else
        printf '"%s" is ok\n' "$string"
    fi
    

    O case ... esaccomando composto é a maneira POSIX de testar uma string em relação a um conjunto de padrões globbing. A variável $patterné usada sem aspas no teste, para que a correspondência não seja feita como uma comparação de string. Se a string não corresponder ao padrão fornecido, ela corresponderá *e o loop será encerrado após a configuração failedcomo true.

    Executando isso renderia

    $ sh script.sh
    "TestString1" does not meet the requirements
    

    Você poderia guardar o teste em uma função assim (o código testa várias strings em um loop, chamando a função):

    #!/bin/sh
    
    test_string () {
        for pattern in '*[[:upper:]]*' '*[[:lower:]]*' '*[[:digit:]]*' '*[[:punct:]]*'
        do
            case $1 in ($pattern) ;; (*) return 1; esac
        done
    }
    
    for string in TestString1 Test.String2 TestString-3; do
        if ! test_string "$string"; then
            printf '"%s" does not meet the requirements\n' "$string"
        else
            printf '"%s" is ok\n' "$string"
        fi
    done
    

    Se você deseja definir LC_ALL=Clocalmente na função, escreva-a como

    test_string () (
        LC_ALL=C
    
        for pattern in '*[[:upper:]]*' '*[[:lower:]]*' '*[[:digit:]]*' '*[[:punct:]]*'
        do
            case $1 in ($pattern) ;; (*) return 1; esac
        done
    )
    

    Observe que o corpo da função agora está em um sub-shell. A configuração LC_ALL=C, portanto, não afetará o valor dessa variável no ambiente de chamada.

    Obtenha a função shell para receber os padrões como argumentos também, e você basicamente obtém a resposta de Stéphane Chazelas (a variante) .

    • 3
  4. bxm
    2019-11-20T15:17:00+08:002019-11-20T15:17:00+08:00

    Inspirado em RomanPerekhrest, mas com alguns pequenos refinamentos para acabar com o pipeline e a substituição de comandos:

    if awk '/[[:lower:]]/ && /[[:upper:]]/ && /[[:digit:]]/ && /[[:punct:]]/ {exit 1}' <<< "$string" ; then
      echo "did not match all requirements"
    else
      echo "looks good to me"
    fi
    
    • 3
  5. Harold Fischer
    2019-11-20T16:10:03+08:002019-11-20T16:10:03+08:00

    Esta é a resposta de RomanPerekhrest reescrita para trabalhar com mawk:

    #!/bin/sh --
    
    string='Aa1!z'
    
    if printf '%s\n' "$string" | LC_ALL=C awk '/[a-z]/ && /[A-Z]/ && /[0-9]/ && /[!-\/:-@[-`{-~]/ {exit 1}'; then
      printf '%s\n' 'String does not meet your requirements'
    else
      printf '%s\n' 'String meets your requirements'
    fi
    

    Ele também pega emprestado da resposta do bxm usando o código de saída do awk em vez de verificar se a saída do awk está vazia.

    • 3
  6. bu5hman
    2019-11-23T10:57:22+08:002019-11-23T10:57:22+08:00

    Roubando descaradamente de @HaroldFischer @bxm e @RomanPerekhrest por uma awksolução pura

    awk -v test="does not meet" '/[a-z]/ && /[A-Z]/ && /[0-9]/ && /[[:punct:]]/ {test="meets"}
        END {print "String "test" your requirements"}' <<<"Aa&0"
    
    • 1
  7. mr.spuratic
    2019-11-23T10:08:27+08:002019-11-23T10:08:27+08:00

    Para completar, uma vez que nenhuma outra resposta menciona o PCRE. Uma limitação do BRE/ERE é que você não pode implementar trivialmente¹ um lógico e para o equivalente lógico "ou" em alternância com |.

    Os padrões PCRE permitem que você crie condições "e" usando asserções de largura zero: antecipar ou antecipar. Esses "não consomem" caracteres, mas restringem a correspondência de padrões antes ou depois. Há muitas maneiras de usá-los, antecipar antecipadamente faz sentido aqui:

    LC_ALL=C pcregrep -q '(?=.*[[:upper:]])(?=.*[[:lower:]])(?=.*[[:digit:]])(?=.*[[:punct:]]).{4,}'
    

    O PCRE aplica 4 "pré-condições" à entrada antes de aplicar a correspondência .{4,}(4 ou mais caracteres, sinta-se à vontade para aumentar ;-). Um ponto a ser observado é que " (?=[[:upper:]])" só inspecionará um único caractere, portanto, cada condição é precedida por " .*" para que toda a entrada seja verificada. pcregreptambém suporta uma localidade via --locale=C.

    Uma vez que o "P" em PCRE significa perl:

    perl -wln -e \
      '/(?=.*[[:upper:]])(?=.*[[:lower:]])(?=.*[[:digit:]])(?=.*[[:punct:]]).{4,}/ && exit 0; exit 1;'
    

    faz a mesma coisa para uma única linha de entrada (não é uma substituição geral para " pcregrep -q").

    Um superconjunto impressionante desse tipo de problema pode ser encontrado aqui: https://stackoverflow.com/questions/469913/regular-expressions-is-there-an-and-operator


    ¹ Você pode expandir um ERE para emular "e" por permutações:

    [[:lower:]].*[[:upper:]].*[[:digit:]].*[[:punct:]]|
    [[:lower:]].*[[:upper:]].*[[:punct:]].*[[:digit:]]|
    [[:lower:]].*[[:digit:]].*[[:upper:]].*[[:punct:]]| ... 20 more lines ...
    [[:punct:]].*[[:digit:]].*[[:upper:]].*[[:lower:]]
    

    Definitivamente não vai ajudar a ser "ineficaz e verboso".

    • 0
  8. R. van Rijn
    2020-11-05T04:07:27+08:002020-11-05T04:07:27+08:00

    Abaixo cria uma senha aleatória com o solicitado. Você pode tornar a senha mais longa substituindo head -c 12por um valor maior.

    while true
    do
      A=$(head /dev/urandom | tr -dc A-Za-z0-9.\'\"$,_! | head -c 12 ; echo '')
    
      [[ ${A} =~ [A-Z] && ${A} =~ [a-z] && ${A} =~ [0-9] && ${A} =~ [.\'\"$,_!] ]] && break
    
    done
    
    • 0

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