我的 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_name
like+
或的值出现问题--help
。正则表达式隐式地锚定在开头(因此是.*
),但不是结束(因此是$
),结果(此处为 0 或 1)除了反映在退出状态中之外,还输出在 stdout 上,因此重定向到 /dev/null。
一些[
实现,例如[
内置的zsh
和 ,yash
有一个=~
运算符(使用 ERE,尽管您可以使用 将其更改为 PCRE zsh
):
if [ "$table_name" '=~' '_[0-9]+$' ]; then
echo Correct
else
echo >&2 Incorrect
fi
bash
,zsh
并在其内部ksh93
有一个运算符=~
[[...]]
运算符,尽管引用的语法和行为因实现而异。最好是使用变量如@BLayer 所示
zsh -o extendedglob
and ksh
(或bash -O extglob
或zsh -o kshglob
支持 glob 子集ksh
)具有 glob 运算符,其功能与正则表达式等效,尽管语法不同。
翻译 RE -> ksh-glob / zsh-glob:
[0-9]
->[0-9]
/[0-9]
x+
->+(x)
/x##
$
或^
-> 隐式/隐式.
->?
.*
->*
(或*(?)
)/*
(或?#
)
所以在ksh
(或bash -O extglob
或zsh -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