如何将字符串与 Bash 中的多个正确值进行比较?

Posted

技术标签:

【中文标题】如何将字符串与 Bash 中的多个正确值进行比较?【英文标题】:How can I compare a string to multiple correct values in Bash? 【发布时间】:2014-02-05 02:28:46 【问题描述】:

我有以下 Bash 脚本:

function get_cms 
    echo "input cms name"
    read cms
    cms=$cms,,
    if [ "$cms" != "wordpress" && "$cms" != "meganto" && "$cms" != "typo3" ]; then
        get_cms
    fi

但无论我输入什么(正确和不正确的值),它都不会再次调用该函数,因为我只想允许这 3 个输入中的 1 个。

我已经用||[ var != value ] or [ var != value1 ] or [ var != value1 ] 尝试过,但没有任何效果。

有人能指出正确的方向吗?

【问题讨论】:

@triplee 我投票决定重新开放。我相信应该关闭另一个问题***.com/questions/22259259。与其他问题相比,这个问题表述得更清楚、来得更快、答案也更好。 @studgeek 感谢您的建议;我现在已经这样做了。 复制品更好恕我直言,因为它有case 作为接受的答案,但我想这主要是个人品味的问题。请注意,case 可以移植回原来的 Bourne shell,当然也可以移植到现代 POSIX shell。也许也可以看看Difference between sh and bash 谢谢。这个也有一个案例答案。这不是被接受的,但就我个人而言,我总是看所有的答案和他们的投票,然后再看哪个被接受(因为后者只是一个人的意见,而投票来自很多人)。 【参考方案1】:

如果主要目的是检查是否在列表中找不到提供的值,也许您可​​以通过“等号”运算符使用 BASH 中内置的扩展正则表达式匹配(另请参阅this answer):

if ! [[ "$cms" =~ ^(wordpress|meganto|typo3)$ ]]; then get_cms ; fi

【讨论】:

为更清晰的答案加分。我更喜欢把!在 [[ ]] 内,但两者同样有效。 非常感谢您的回答。帮我解决了工作中的一个问题! 由于某种原因这对我不起作用。我正在使用 (id=2015|id=2016),如果变量在任何地方都有这些字符串之一,我希望执行 IF,但它不起作用【参考方案2】:

而不是说:

if [ "$cms" != "wordpress" && "$cms" != "meganto" && "$cms" != "typo3" ]; then

说:

if [[ "$cms" != "wordpress" && "$cms" != "meganto" && "$cms" != "typo3" ]]; then

您可能还想参考Conditional Constructs。

【讨论】:

一次又一次地重复"$cms" != 不是很干。在任何情况下(例如"$csm" !=),它都会为拼写错误留下空间,并且您没有编译器可以在 shell 中向您指出这一点。最好尽量避免重复变量名。 (请参阅我的答案以了解如何做到这一点。) 我不得不在最后删除;,所以不是... "typo3" ]]; then,而是..."typo3"]] then,但除此之外这工作得很好。【参考方案3】:

也许您最好将case 用于此类列表:

case "$cms" in
  wordpress|meganto|typo3)
    do_your_else_case
    ;;
  *)
    do_your_then_case
    ;;
esac

我认为这样的列表很长,可读性更好。

如果您仍然喜欢if,您可以通过两种方式使用单括号:

if [ "$cms" != wordpress -a "$cms" != meganto -a "$cms" != typo3 ]; then

if [ "$cms" != wordpress ] && [ "$cms" != meganto ] && [ "$cms" != typo3 ]; then

【讨论】:

效果很好!顺便说一句,不是“do_your_then|else_case”文本提示倒置了吗? :) OP 正在使用 ≠ (!=) 制定他的原始条件;我与case 的版本是匹配的(所以它是使用与= 的比较),因此是反转。 漂亮的解决方案。像这样的用例有什么问题吗? Shell 编程永远不会没有“陷阱”,正如您所说的那样;-) 我可以想到使用带有空格或管道符号或其他奇怪字符的比较字符串的问题;在这种情况下,您需要正确引用它们。这需要时间来找到正确的语法,并且至少对于代码的下一个维护者来说很难阅读。 @Alfe,参见pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html 中的[OB XSI] 符号。如果您单击它,它会将您链接到一个定义: 在本卷 POSIX.1-2008 的未来版本中可能会删除所描述的功能。严格符合 POSIX 应用程序和严格符合 XSI 应用程序不得使用过时的功能。我怀疑 GNU coreutils 或 bash 是否真的会删除它,但它计划在将来不再是 POSIX 强制行为(出于好的原因,考虑到引入的歧义)。【参考方案4】:

正如@Renich 建议的那样(但不幸的是,一个重要的错字尚未修复),您还可以使用扩展通配符进行模式匹配。因此,您可以在 bash 比较中使用与命令参数(例如 ls *.pdf)中的文件匹配的相同模式。

对于您的特定情况,您可以执行以下操作。

if [[ "$cms" != @(wordpress|magento|typo3) ]]

@ 表示“匹配给定模式之一”。所以这基本上是说cms 不等于 'wordpress' OR 'magento' OR 'typo3'。在正常的正则表达式语法中,@ 类似于 ^(wordpress|magento|typo3)$

Mitch Frazier 在 Linux 杂志上有两篇关于 Pattern Matching In Bash 和 Bash Extended Globbing 的好文章。

有关扩展通配符的更多背景信息,请参阅Pattern Matching (Bash Reference Manual)。

【讨论】:

【参考方案5】:

这是我的解决方案

if [[ "$cms" != @(wordpress|magento|typo3) ]]; then

【讨论】:

不是 + 而是 @ 在您的 extglob 中。否则你会得到错误的结果,例如,wordpressmagentotypo3typo3

以上是关于如何将字符串与 Bash 中的多个正确值进行比较?的主要内容,如果未能解决你的问题,请参考以下文章

如何在谷歌电子表格中将多个单元格与一行中的两个可能值进行比较?

BASH将Linux版本与数字进行比较? [重复]

将一个表中的多个值与另一个表中的多个值进行比较

如何将地图中的值与阈值进行比较并将大于最小阈值的值放入集合中

JET OLEDB 参数如何将字符串与 Access DB 中的文本字段进行比较

Bash将命令输出与字符串进行比较[重复]