代码/模块,用于评估在Linux上的awk或bash中使用的布尔表达式

时间:2015-01-09 07:45:51

标签: linux bash parsing awk boolean-expression

我正在使用awk脚本进行一些bash搜索许多文件,并返回符合各种条件组合的各种行组合。

我想通过某种方式为我的脚本添加功能,以便能够处理简单但通用的布尔“查询”表达式 - 例如:

A AND (B OR C) AND NOT D

其中A,B,C和D是bash或awk变量,其值为TRUE=0FALSE!=0,反之亦然。

我的代码会设置每个变量,然后使用这些变量将布尔表达式传递给可以评估它的东西。

我真的不需要像嵌套括号那样非常花哨的东西,但是一个级别真的会有所帮助。我不需要广泛的表达式错误检查/恢复。如果我写了一个不好的表达式,那就是我的问题,只要它不会像bash / awk语法错误一样完全杀死我的脚本。

解决方案可以是bash或awk本机,也可以是从任一语言中调用的外部程序,返回true或false(0/1)。

我知道如何使用if语句等对这些事情进行硬编码,但我需要能够为每次搜索更改条件,因此无法对其进行硬编码。

我绝对不知道用lex / yacc这样的东西来推广我自己的解析器。

sedfindgrep这样的工具很棒,但是(至少是它们自己),它们不会做我想要的,而且对于使用语法过于挑剔用于编写即席查询。

作为一种替代方案,我正在考虑尝试将我的查询转换为简单的数学,并将它们通过bash中的(( query )) - 例如对于上面的示例(不使用完全防御语法使示例变得丑陋,并且所有变量都设置为1表示true,0表示false。)

(( $A * ($B + $C) * (! $D) ))

1 个答案:

答案 0 :(得分:1)

我并没有确切地知道你的目标是什么,但我创建了一个小的脚本来获取任何布尔表达式并编写其真值表。也许这有帮助。它处理任何大括号,AND,OR和NOT表达式。变量是以字母开头的任何内容(在您设置的语言上)。唯一需要改变的是COND变量。它也可以从命令行设置。仅当您的支持关联数组(declare -A)时,它才有效。

这是脚本:

#!/usr/bin/bash

COND="A AND (B OR C) AND NOT DD"

# Convert to bash syntax
cond=${COND// AND / && }
cond=${cond// OR / || }
cond=${cond// NOT / ! }
cond=${cond//^NOT /! }
cond=${cond//(/ ( }
cond=${cond//)/ ) }
# Now $cond can be used in eval adding "((..))" around it.
# The rest of the script prints the complete truth-table

# Collect unique variables
declare -A hvars
for var in $cond; do
  [[ $var =~ ^[[:alpha:]] ]] && hvars[$var]=1
done
# Make vars array
vars=(${!hvars[@]})
# Number of variables
n=${#vars[@]}
# Number or rows in truth-table
((N=1<<n))

echo "${vars[@]} | $COND"
for ((i=0; i<N;++i)); do
  for ((b=0; b<n; ++b)) do
    var=${vars[b]}
    ((val=i & 1<<(n-1-b) ? 1 : 0))
    printf "%*d " ${#var} $val
    eval "(($var=$val))"
  done
  eval "((r=$cond))"
  echo "| $r";
done

输出:

A B C DD | A AND (B OR C) AND NOT DD
0 0 0  0 | 0
0 0 0  1 | 0
0 0 1  0 | 0
0 0 1  1 | 0
0 1 0  0 | 0
0 1 0  1 | 0
0 1 1  0 | 0
0 1 1  1 | 0
1 0 0  0 | 0
1 0 0  1 | 0
1 0 1  0 | 1
1 0 1  1 | 0
1 1 0  0 | 1
1 1 0  1 | 0
1 1 1  0 | 1
1 1 1  1 | 0

它将人类可读格式的条件转换为格式(AND&&OR||NOT至{ {1}}以及!(周围设置了一个空格。不要在)中误用))。)。然后它收集所有唯一变量。然后计算真值表的大小。然后为每一行创建一个循环。在该循环内部,它创建一个嵌套循环来计算每个变量的值并设置该值。在主循环结束时计算表达式的值。

这不是防弹。不要在变量名称中使用特殊变量(evalDD=XX)。

因此,您的代码设置已使用的变量,然后在A'B中调用已转换的条件(请参阅cond)(请参阅上一页eval),以评估条件正常。然后eval变量可以用于您自己的目的......

我希望这有帮助!