当我在 shell 脚本中运行以下行时:
/sbin/iptables-save -t filter |
grep -- "-A INPUT" |
grep -v "fail2ban-\|f2b-" |
sed -e "s#^-A#apply_rule /sbin/iptables -D#g" |
xargs -0 echo -e "`declare -f apply_rule`\n" |
/bin/bash
它所做的只是检查
-A INPUT -s IP -j DROP
统治iptables-save
.
说,
-A INPUT -s 198.55.114.215 -j DROP
然后将其转换为Delete
版本并传递给xargs
apply_rule /sbin/iptables -D INPUT -s 198.55.114.215 -j DROP
但是我有2000
-A
规则iptables-save
,当我尝试运行它时,上面的行会抛出错误:
xargs: argument line too long
我检查了限制并
echo $(( $getconf ARG_MAX
结果是:
2621440
有规则时不会发生此错误1000
-A
,但2000
-A
有规则时iptables-save
会产生此问题。
实际错误是:
xargs -0 echo -e "`declare -f apply_rule`\n"
我该如何解决这个问题?
答案1
我们来看看管道:
/sbin/iptables-save -t filter |
grep -- "-A INPUT" |
grep -v "fail2ban-\|f2b-" |
sed -e "s#^-A#apply_rule /sbin/iptables -D#g" |
xargs -0 echo -e "`declare -f apply_rule`\n" |
/bin/bash
iptables
生成一个规则列表,每行一个规则。换句话说,每个规则都由换行符 分隔\n
。使用如图所示的选项,grep
和sed
命令一次处理一行输入。换句话说,他们还期望换行符分隔的输入并生成换行符分隔的输出。 xargs -0
然而期待空分隔的输入。由于前面的命令的输出不包含空字符,因此xargs
尝试将其所有标准输入作为单个项目立即读取。这就是为什么它会生成错误消息“参数行太长”。
解决方案是告诉xargs
我们期待换行符分隔的输入。为此,我们添加选项-d '\n'
。然而,我们也希望它一次只处理一行。为此,我们需要指定-n1
.把这一切放在一起:
/sbin/iptables-save -t filter |
grep -- "-A INPUT" |
grep -v "fail2ban-\|f2b-" |
sed -e "s#^-A#apply_rule /sbin/iptables -D#g" |
xargs -n1 -d '\n' echo -e "`declare -f apply_rule`\n" |
/bin/bash
文档
从man xargs
:
-ddelim
输入项以指定字符终止。引号和反斜杠并不特殊;输入中的每个字符均按字面意思处理。禁用文件结束字符串,该字符串的处理方式与任何其他参数一样。当输入仅由换行符分隔的项目组成时,可以使用此选项,尽管在可能的情况下设计程序以使用 --null 几乎总是更好。指定的分隔符可以是单个字符、C 样式字符转义符(例如 \n)或者八进制或十六进制转义码。八进制和十六进制转义码被理解为 printf 命令。不支持多字节字符。-nmax-args
每个命令行最多使用 max-args 个参数。如果超出大小(请参阅 -s 选项),则将使用少于 max-args 的参数,除非给出 -x 选项,在这种情况下 xargs 将退出。