Bash 脚本中的 Grep 无法正常工作

Bash 脚本中的 Grep 无法正常工作

我知道互联网上有很多类似的问题,但我找不到针对我的具体问题的解决方案。

我为一项作业编写了这个脚本,我想找出哪些组合在 HTML 中返回 UNLOCKED 结果。

#!/bin/bash
for ((x4=0;x4<=4;x4++)); do
  for ((x3=0;x3<=4;x3++)); do
    for ((x2=0;x2<=4;x2++)); do
      for ((x1=0;x1<=4;x1++)); do
echo $x1 $x2 $x3 $x4
eval curl http://www.artemiosv.info/21.php?p1=$x1;p2=$x2;p3=$x3;p4=$x4
  | grep -oP '<BODY>*[\s\S]*</BODY>'
done
done
done
done

将脚本的输出重定向到文件后,返回的结果的第一行是:

0 0 0 0
<HTML><BODY>LOCKED</BODY></HTML>1 0 0 0
<HTML><BODY>LOCKED</BODY></HTML>2 0 0 0
<HTML><BODY>LOCKED</BODY></HTML>3 0 0 0

从 HTML 代码来看,这是卷曲命令,我只想要主文本,在这些行的情况下是 LOCKED。但我使用的正则表达式似乎不起作用,而在脚本之外测试相同的模式则工作正常。HTML 的预期结果应该是 LOCKED、UNLO​​CKED,我认为你找到了秘密。

为什么grep脚本内部存在此问题,而外部运行正常?我该如何修复它?

答案1

抱歉,我可能忽略了一些东西。

在 shell 中检查你的 curl 命令。删除 grep 并运行它。当我这样做时,我可以看到整个返回结果。我得到了数百次返回结果

<HTML><BODY>LOCKED</BODY></HTML>

我认为这表明该网站阻止了你抓取它。哎呀,只需浏览一下:

http://www.artemiosv.info/21.php?p1=1;p2=2;p3=3;p4=4

它返回一个只显示“已锁定”的页面

关于 grep 的问题,grep 会选择具有字符模式的行。它不会在其中选择子字符串,这就是 sed 之类的工具的用途。我认为 grep 正好满足您的要求。您说它在测试用例中有效,但我无法想象它是如何工作的。

为什么不采取简单的方法,运行网络抓取并将文件保存在您的 PC 中,然后对它们执行 grep/sed/awk 魔法。这是确保您在检索内容时实际获得什么的唯一方法。而且这是您从 grep 或 sed 获得所需内容的更可能的方法。一旦您知道自己在做什么以及拥有什么,管道就很方便。我怀疑这里两种情况都不成立。

答案2

您只需更改正则表达式,以便排除 HTML 标记。由于您使用的是 Perl 兼容正则表达式,因此您可以使用\K表示“丢弃到目前为止匹配的任何内容”的 来丢弃<BODY>,以及积极展望丢弃</BODY>。您还可以使用括号扩展来代替更麻烦的for((var=0;var<=lim;var++))语法:

for x4 in {0..4}; do
  for x3 in {0..4}; do
    for x2 in {0..4}; do
      for x1 in {0..4}; do
        curl "http://www.artemiosv.info/21.php?p1=$x1;p2=$x2;p3=$x3;p4=$x4" 2>/dev/null |
            grep -oP '<BODY>\K[\s\S]*(?=</BODY>)'
      done
    done
  done
done

或者,如果您想要 HTML 内容和 4 个变量的值,请使用以下命令:

for x4 in {0..4}; do
 for x3 in {0..4}; do
  for x2 in {0..4}; do
   for x1 in {0..4}; do
     printf '%s : %s\n' "$x1 $x2 $x3 $x4" \
        "$(curl "http://www.artemiosv.info/21.php?p1=$x1;p2=$x2;p3=$x3;p4=$x4" 2>/dev/null |
           grep -oP '<BODY>\K[\s\S]*(?=</BODY>)')"
   done
  done
done

完毕

请注意,我还删除了,eval因为它没有任何用处。您只需要重定向 stderr。

最后,您还可以将curl命令发送到后台,以便可以并行运行多个命令。这些命令不是很繁重,因此您的机器应该能够处理它们,这将大大加快脚本的速度。只需&在行末添加printf ...

printf '%s : %s\n' "$x1 $x2 $x3 $x4" \
        "$(curl "http://www.artemiosv.info/21.php?p1=$x1;p2=$x2;p3=$x3;p4=$x4" 2>/dev/null |
            grep -oP '<BODY>\K[\s\S]*(?=</BODY>)')" &

但请注意,您尝试下载的网站似乎无法处理多个连续的请求。即使不并行运行,某些请求也会返回空结果(如果手动运行则有效),而并行运行时空结果的数量会成倍增加。您可能需要与老师讨论如何解决这个问题。

相关内容