表达式中的语法错误(错误标记为“INPUT(策略接受)| cut -d ' ' -f1)

Syntax error in expression (error token is "INPUT (policy ACCEPT) | cut -d ' ' -f1)

嗨,我最近开始学习 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


此脚本中存在几个语法问题。在行中:

 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 脚本中常见错误的简单工具。

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

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

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