【问题标题】:Syntax error in expression (error token is "INPUT (policy ACCEPT) | cut -d ' ' -f1)表达式中的语法错误(错误标记为“INPUT (policy ACCEPT) | cut -d ' ' -f1)
【发布时间】:2021-01-29 06:20:29
【问题描述】:

嗨,我最近开始学习 bash 脚本,因为我很“绿色”,可以这么说,我希望能得到一些帮助。我有这个问题,我似乎无法自己解决。我希望这个程序通读每一行以检查给定 IP 地址是否有任何 iptables 规则。如果有:取行号,然后用 iptables -R INPUT $lineNumberHere -s $IP_ADDRESS -j $newPolicy 修改或删除。

但是程序开始读取第一行并将行号注册为“Chain”和“num”,这会导致错误。有没有绕过这两行的方法?

只是为了澄清。我正在以 root 身份运行程序


# The IP address is listen in rules

        # Find the line number of the rule
        echo ""
        echo "The IP allready has a rule in iptables"
        iptables -L INPUT --line-numbers | while read line; do
                echo ""
                echo "Checking line: $line"
                LINE_NUMBER=$(($line | cut -d " " -f1))
                BANNED_IP=$(($line | cut -d " " -f4 | cut -d "/" -f1))
                re='^[0-9]+$'
                if [[ "$LINE_NUMBER" =~ $re ]]; then

                        echo "Line nr. $LINE_NUMBER"
                        if [ "$IP_ADDRESS"="$BANNED_IP" ]; then
                                echo "Changing status to BANNED"
                                iptables -R INPUT "$LINE_NUMBER" -s "$IP_ADDRESS" -j DROP
                        fi
                else
                        echo "error: Not a number" >&2
                        continue;

                fi

        done


【问题讨论】:

    标签: linux bash shell ssh iptables


    【解决方案1】:

    这个脚本有几个语法问题。在行中:

     LINE_NUMBER=$(($line | cut -d " " -f1))
     BANNED_IP=$(($line | cut -d " " -f4 | cut -d "/" -f1))
    

    ...有两个问题:$(( )) 将其内容评估为算术表达式,而不是命令(这就是您收到“表达式中的语法错误”错误的原因)。要运行命令并捕获其输出,您需要单级括号:$( ) 而不是 $(( ))

    另一个问题是管道内部的命令管道,管道的元素必须是命令,$line 不是一个,它只是数据。你想要像$(echo "$line" | cut ...) 这样的东西。

    我立即看到的另一个问题是在这一行:

    if [ "$IP_ADDRESS"="$BANNED_IP" ]; then
    

    = 运算符周围需要空格;没有它们,它根本不会被识别为运算符,只是单个长字符串的一部分。所以改用这个:

    if [ "$IP_ADDRESS" = "$BANNED_IP" ]; then
    

    可能还有其他问题,这些只是我在检查时发现的问题。顺便说一句,我推荐 shellcheck.net 作为一个简单的工具来指出 bash 脚本中的常见错误。

    【讨论】:

    • 感谢您的反馈。我会在早上第一件事尝试运行它!
    【解决方案2】:

    虽然 Gordon 已经回答了您提出的问题,但我想提出改进建议。你不需要运行多个cuts 来解析这些数据,shell 可以很好地完成。此外,由于iptables 输出的两个标题行不包含行号是正常的,因此我不会输出会警告和混淆用户的错误消息,只需忽略(不要使用)这些行:

    iptables -L INPUT --line-numbers | while read ln _ _ ip _; do ip=${ip%/*} 
        if [[ $ln =~ ^[0-9]+$ && $ip = $IP_ADDRESS ]]; then
            echo Changing $IP_ADDRESS to banned
            iptables -R INPUT "$LINE_NUMBER" -s "$IP_ADDRESS" -j DROP
        fi
    done
    

    注意[[ ]] 是特殊语法,不需要" " 引用的变量,尽管您可以使用它们来保持一致性。但不是在正则表达式上,因为引用正则表达式会使其成为文字匹配。

    【讨论】:

    • 双引号在= 比较的右侧在[[ ]] 条件表达式中也很重要——没有它们,右侧被视为全局(通配符)模式,但是与他们一起,它被视为文字字符串。在这种情况下,模式匹配功能实际上可能很有用(例如IP_ADDRESS='192.0.2.*'),所以不加引号是有道理的——但在这种情况下,接下来的两行应该使用$ip而不是$IP_ADDRESS,所以他们禁止特定的ip地址。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多