正则表达式仅检查下划线后面是否存在数字而不是字符

正则表达式仅检查下划线后面是否存在数字而不是字符

我的 shell 脚本中有 if 循环,它将检查表名是否包含任何整数,这是我指定的条件:

if [[ "$able_name" == *[0-9]* ]] 

一般来说,表名会是这样的:

tablename_000 

或者

tablename_001 

但我有一个新文件,其名称类似于table_V2.由于名称与正则表达式匹配,因此它正在进入此循环。我怎样才能避免这种情况?if仅当下划线后面存在整数而不是任何其他字符时,它才应进入循环。

答案1

使用标准sh语法:

case ${table_name##*_} in
  ("$table_name" | "" | *[!0-9]*) echo >&2 incorrect;;
  (*) echo correct;;
esac

即检查$table_name删除最右边的所有内容_既不是$table_name它本身(这意味着$table_name没有_),也不是空字符串,也不包含非数字字符。

将字符串与正则表达式进行匹配的标准命令expr虽然存在一些问题,并且代码不清晰:

if expr " $table_name" : '.*_[0-9]\{1,\}$' > /dev/null; then
  echo Correct
else
  echo >&2 Incorrect
fi

前导空格是为了避免$table_namelike+或的值出现问题--help。正则表达式隐式地锚定在开头(因此是.*),但不是结束(因此是$),结果(此处为 0 或 1)除了反映在退出状态中之外,还输出在 stdout 上,因此重定向到 /dev/null。

一些[实现,例如[内置的zsh和 ,yash有一个=~运算符(使用 ERE,尽管您可以使用 将其更改为 PCRE zsh):

if [ "$table_name" '=~' '_[0-9]+$' ]; then
   echo Correct
else
   echo >&2 Incorrect
fi

bashzsh并在其内部ksh93有一个运算符=~[[...]]运算符,尽管引用的语法和行为因实现而异。最好是使用变量如@BLayer 所示

zsh -o extendedgloband ksh(或bash -O extglobzsh -o kshglob支持 glob 子集ksh)具有 glob 运算符,其功能与正则表达式等效,尽管语法不同。

翻译 RE -> ksh-glob / zsh-glob:

  • [0-9]-> [0-9]/[0-9]
  • x+-> +(x)/x##
  • $^-> 隐式/隐式
  • .->?
  • .*-> *(或*(?))/ *(或?#

所以在ksh(或bash -O extglobzsh -o kshglob) 中:

case $table_name in
  (*_+([0-9]) echo correct;;
  (*) echo >&2 incorrect;;
esac

zsh -o extendedglob

case $table_name in
  (*_[0-9]##) echo correct;;
  (*) echo >&2 incorrect;;
esac

zsh还有<x-y>扩展的 glob 运算符来匹配从x到 的十进制数字y,因此您也可以编写它(*_<->) echo correct

=在这些 shell 中,这些 glob 也可以用在aka运算符的右侧== [[...]]

答案2

可能是最简单的正则表达式:

if [[ "$file" =~ _[0-9]+$ ]]
then
    echo OK $file
fi

答案3

有很多方法可以做到这一点。这是一个采用传统正则表达式方式的 Bash 版本(或者至少是 Bash 最接近的版本):

pattern='^tablename_[[:digit:]]+$'
if [[ $filename =~ $pattern ]]; then
    echo "Filename $filename is valid"
fi

一些注意事项:

  • 对于除最简单的正则表达式之外的所有正则表达式,建议使用变量,就像我在这里使用pattern.即使没有对内部表达式应用分词或路径名扩展,[[ ]]也会有波形符、变量和算术扩展以及进程和命令替换。使用内联正则表达式很容易得到不正确或意外的结果。
  • 我正在使用 POSIX 字符类,[:digit:]0-9也很好。我认为这里的大多数其他答案都会使用后者,并且为了完整起见,值得展示前者

评论:这个主题有如此多的变体(仅在这个线程中)这一事实是有些人不喜欢sh/的原因之一bash ......以及为什么我喜欢他们的原因之一。:)

答案4

建议为此使用正则表达式选项,但也可以使用仅包含数字的普通 glob。例如你可以做类似的事情

for file in tablename_[0-9]*; do
    [ -f "$file" ] || continue
    printf "%s\n" "$file"
done

使用 中的正则表达式运算符bash,您可以执行类似的操作,

for file in tablename_*; do
    if [[ $file =~ _([[:digit:]]+)$ ]]; then
        printf "%s\n" "$file"
    fi
done

相关内容