冒号字符搞乱了我在 Bash 中的模式匹配

冒号字符搞乱了我在 Bash 中的模式匹配

我有一个变量$line,它可以包含以下任何字符串:

  • line="READ CACHE IS: ENABLED"
  • line="BLOCKS READ CACHE AND SENT TO INITIATOR = 2489338280"
  • line="ECC REREADS/ ERRORS ALGORITHM PROCESSED UNCORRECTED"
  • line="READ: 2513550726 22 0 2513550748 2513550748 27768.965 0"
  • line="1 RAW_READ_ERROR_RATE PO-R-- 100 100 016 - 0"
  • line="0x22 GPL R/O 1 READ STREAM ERROR LOG"
  • line="READ: DISABLED"

我有一个脚本将$line变量与某些模式进行比较:

if [[ ${line} == *"RAW_READ_ERROR_RATE"* ]] || 
[[ ${line} == "READ\:"* ]] && 
[[ ${line} != *"READ: DISABLED"* ]]; then

devReadErr=$(echo "$line" | awk '{print $8}')

问题就在这里。结肠把一切都搞砸了。我已经尝试了格式化模式的所有可能方法,以满足line="1 RAW_READ_ERROR_RATE PO-R-- 100 100 016 - 0"line="READ: 2513550726 22 0 2513550748 2513550748 27768.965 0" 当我转义 : 时的两种可能性,如上所示。我可以满足,line="1 RAW_READ_ERROR_RATE PO-R-- 100 100 016 - 0"但不能line="READ: 2513550726 22 0 2513550748 2513550748 27768.965 0"。如果我拿走逃避,那么我line="READ: 2513550726 22 0 2513550748 2513550748 27768.965 0"不满足line="1 RAW_READ_ERROR_RATE PO-R-- 100 100 016 - 0"

示例运行 1:

line="1 RAW_READ_ERROR_RATE PO-R-- 100 100 016 - 0"

        if [[ ${line} == *"RAW_READ_ERROR_RATE"* ]] || 
           [[ ${line} == "READ\:"* ]] && 
           [[ ${line} != *"READ: DISABLED"* ]]; then

          devReadErr=$(echo "$line" | awk '{print $8}')
        fi

echo $devReadErr

运行 1 的输出:

0

示例运行 2:

line="READ: 2513550726 22 0 2513550748 2513550748 27768.965 0"

        if [[ ${line} == *"RAW_READ_ERROR_RATE"* ]] || 
           [[ ${line} == "READ\:"* ]] && 
           [[ ${line} != *"READ: DISABLED"* ]]; then

          devReadErr=$(echo "$line" | awk '{print $8}')
        fi

echo $devReadErr

运行 2 的输出:

<null>

示例运行 3:

line="READ: 2513550726 22 0 2513550748 2513550748 27768.965 0"

        if [[ ${line} == *"RAW_READ_ERROR_RATE"* ]] || 
           [[ ${line} == "READ:"* ]] && 
           [[ ${line} != *"READ: DISABLED"* ]]; then

          devReadErr=$(echo "$line" | awk '{print $8}')
        fi

echo $devReadErr

运行 3 的输出:

0

我如何才能两全其美?

答案1

您应该在第二个测试中删除\前面的:,否则它将尝试与文字\字符匹配。

这些不是您正在执行的正则表达式匹配,而是 shell 通配模式匹配(就像您*在模式中使用时在命令行上一样)。在这种情况下这并不重要。

我假设您想从前两个字符串中提取 20 并将其存储在 中devReadErr,但在该行读取时不存储READ: DISABLED。如果\删除,这正是您的代码所做的:

if  [[ ${line} == *"RAW_READ_ERROR_RATE"* ]] ||
    [[ ${line} == "READ:"* ]] &&
    [[ ${line} != *"READ: DISABLED"* ]]; then

    devReadErr=$(echo "$line" | awk '{print $2}')

fi

做同样事情的另一种方法:

if [[ "$line" != *'DISABLED' ]]; then
    devReadErr=${line##* }
fi

$line如果字符串不以单词 结尾,则将数字提取为最后一个空格字符后面的字符串DISABLED。这避免了echoawk

如果这是逐行解析文件的较大循环的一部分,那么我建议使用awk旨在解析文本的其他语言编写它。参见,例如, 为什么使用 shell 循环处理文本被认为是不好的做法?

答案2

我怀疑你想要:

if [[ $line = *RAW_READ_ERROR_RATE* || 
      $line = READ:* && $line != *"READ: DISABLED"* ]]; then

运算&& [[...]]符优先于||&& 运算符的优先级与 相同||

或者明确地说:

if [[ $line = *RAW_READ_ERROR_RATE* || 
      ($line = READ:* && $line != *"READ: DISABLED"*) ]]; then

或者使用&&/ ||shell 运算符和多个[[...]]s:

if [[ $line = *RAW_READ_ERROR_RATE* ]] || { 
      [[ $line = READ:* ]] && [[ $line != *"READ: DISABLED"* ]]; }; then

或者更改顺序:

if [[ $line = READ:* ]] && [[ $line != *"READ: DISABLED"* ]] ||
   [[ $line = *RAW_READ_ERROR_RATE* ]]; then

或者使用匹配所有内容的模式:

if [[ $line = @(*RAW_READ_ERROR_RATE*|!(!(*READ:*)|*READ:\ DISABLED*)) ]]; then

如果没有括号/大括号,您的内容将被解读为:

if [[ ($line = *RAW_READ_ERROR_RATE* || 
     $line = READ:*) && $line != *"READ: DISABLED"* ]]; then

这不应该阻止它匹配包含 while 的行RAW_READ_ERROR_RATE,前提是它们不包含READ: DISABLED.

相关内容