我有一个变量$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
。这避免了echo
和awk
。
如果这是逐行解析文件的较大循环的一部分,那么我建议使用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
.