如何确保一个字符串至少包含一个大写字母、一个小写字母、一个数字和一个标点符号?

Har*_*her 5 shell posix pattern-matching

这就是我现在用来完成工作的方法:

#!/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
Run Code Online (Sandbox Code Playgroud)

这是非常低效和冗长的。有一个更好的方法吗?

Rom*_*est 7

使用灵活的awk模式匹配:

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
Run Code Online (Sandbox Code Playgroud)

  • +1,但是 OP 的代码有一个 `/bin/sh` shebang 行,并且您正在通过 `[[` 使用 bashism (4认同)

Sté*_*las 7

一次调用awk和不调用管道:

#! /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
Run Code Online (Sandbox Code Playgroud)

那是 POSIX 但请注意,mawk尚不支持 POSIX 字符类。在--不需要与POSIX兼容awk秒,但会在较旧版本的busybox的awk(这将窒息的值$string 是下手-)。

使用caseshell 构造的该函数的变体:

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

但是请注意,在脚本中间更改 shell 的语言环境不适用于所有sh实现(因此,如果您希望将输入视为在C 语言环境字符集和字符类仅匹配 POSIX 指定的字符集)。