【问题标题】:Sed: execute alternative command when output from previous one is emptysed:当前一个输出为空时执行替代命令
【发布时间】:2019-05-19 08:22:00
【问题描述】:

我想修改 dig 命令以自动对我在输出中收到的任何 A 记录应用反向查找。

因此,我创建了以下函数:

dt ()
{
    remove=$(echo $@ |  sed 's^https*^^' | sed 's^[,/*:]^^g' );
    dig any +trace +nocl +nodnssec $remove | sed "s/\($remove.*A\s*\([0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\)\)/dig -x \2 +short | xargs echo \"\1 ->\"/e"
}

使用此代码,我有以下输出(仅显示 A 记录部分以避免问题变得更大):

domain.com.      1200    A        198.54.115.174 -> server224-3.web-hosting.com.

但是,现在我还需要使用从 dig 输出收到的 IP 进行 whois 查找,但前提是 dig -x \2 +short 没有给出任何结果(stackoverflow.com 可以是具有 A 的域的一个很好的例子没有 PTR 的记录)。

我尝试了这样的方法来检查常规host 命令的退出代码(因为dig 意味着即使输出为空也成功)并根据结果执行正确的命令:

dig any +trace +nocl +nodnssec "$remove" | sed -e "s/\($remove.*A\s*\([0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\)\)/echo -n \"\1 -> \"; host \2 | grep -q ''; if [ ${PIPESTATUS[0]} -eq 0 ]; then dig -x \2 +short; else whois \2 | grep 'network:Network-Name:';fi; /e"

但似乎 sed 以某种方式影响了 ${PIPESTATUS[0]} 数组的值。

我想在 sed 中进行这些修改,因为我需要一些可以随时随地打印行的东西。如果我使用变量并修改它们的输出,函数会运行得更慢,至少在视觉上是这样。

也许awk 可以在这里使用,但我不确定应该如何使用此命令编写代码。

有没有办法解决这个问题? sed 可以用于此目的还是应该使用其他工具?谢谢。

【问题讨论】:

  • 你有:remove=$(echo $@ | sed 's^https*^^' | sed 's^[,/*:]^^g' );——你应该考虑:remove=$(echo "$@" | sed -e 's^https*^^' -e 's^[,/*:]^^g' );。更改使用一个 sed 调用而不是两个;这是无可争议的。使用$@ unquoted 通常是一个危险的信号,但它确实会使空白和换行符变平,所以它不是绝对错误的。未加引号,$@$* 没有区别;引用,有。目前尚不清楚那里最好的是什么,但"$@" 通常是引用参数的正确方法。 ——这些都与你的问题无关。
  • 我只是犯了一个错误,试图查看您的 sed 脚本的最右端。很抱歉,它们太长且难以阅读,对我来说不是很有趣。至少,当我在工作并且需要在编译完成后立即做其他事情时,不会。
  • @JonathanLeffler 感谢您的建议。很抱歉没有为 sed 使用“-E”参数(这会使正则表达式更小更容易查看)。只是想确保我遗漏了任何可能会在该行中添加更多错误的编辑,因为它是在大约 9 个月前编写的(当时我不知道 ERE 选项),所以我可能还需要查看正则表达式本身.
  • 另外,我肯定会根据您的建议添加“-e”标志来优化“删除”变量的行。我也在试图弄清楚如何使我的代码更具可读性。很可能我至少应该用“\”或其他东西换行。
  • 我认为您正在使用 sed 脚本编写一个 shell 脚本(片段)。我想知道你是否会更好地使用一个实际的第二个脚本来调用一些(一个,两个,......)适当的参数。如果它不可读,则它是不可维护的。这可能是正确的,但很难说。这些天我似乎很不寻常,但我写了很多脚本,而且大多数都不是很大,至少在刚开始的时候是这样。我的$HOME/bin 目录中有超过 600 个程序(脚本和可执行文件)。

标签: bash awk sed whois dig


【解决方案1】:

The good old' bash 为您提供各种工具 grepawkxargswhile read 等等。使用 sede 命令并在内部检查 PIPESTATUS 并执行 xargs.... 只是不可读并且读起来太长了。我不清楚你想做什么,因为一行发生了太多事情。

dig 命令成功时结果为零 - 您可以检查它的输出,如果它“失败”时长度为零。

考虑以下脚本:

dt () {
    remove=$(
        <<<$1 \
        sed 's#^http[s]?://\([^/]*\).*#\1#'
    )
        dig any +trace +nocl +nodnssec "$remove" |
        tr -s '\t' |
        awk -v "remove=${remove}." '{
                if ($1 == remove && $3 == "A") {
                        print
                }
        }' |
        while IFS= read -r line; do
                IFS=$'\t' read -r _ _ _ ip _ <<<"$line"
                if ! dig_result=$(dig -x "$ip" +short); then
                        echo "Dig error" >&2
                        exit 1
                fi
                if [ -z "$dig_result" ]; then
                        printf "%s -> no-result-from-dig\n" "$line"
                else
                        printf "%s -> %s\n" "$line" "$dig_result"
                fi
        done
}
  1. 首先运行dig。请注意,"$remove" 已被引用。
  2. 只是一个预防措施 - 我压缩了输出中的制表符。
  3. 然后我过滤 - 第一列应该有一个带点的"$remove".,第三列应该是一个"A"
  4. 然后对于每一行(因为有很多)
  5. 我得到了 IP 地址(好吧,也许ip=$(&lt;&lt;&lt;"$line" cut -f4) 会更简洁)。
  6. 我使用 ip 地址从dig -x 得到结果
  7. 如果结果为空,我打印“no-result-from-dig”,如果不是,我打印结果。

跑步:

dt stackoverflow.com
dt google.pl

输出:

stackoverflow.com.      300     A       151.101.65.69 -> no-result-from-dig
stackoverflow.com.      300     A       151.101.193.69 -> no-result-from-dig
stackoverflow.com.      300     A       151.101.129.69 -> no-result-from-dig
stackoverflow.com.      300     A       151.101.1.69 -> no-result-from-dig
google.pl.      300     A       216.58.215.67 -> waw02s16-in-f3.1e100.net.

您的命令不起作用的原因是 $PIPESTATUS" 引号内被引用,因此在运行 shell 之前被扩展。您应该转义 $,这样就是 \$PIPESTATUS 或将其传递到非扩展单引号 " ... "'$PIPESTATUS'" ... " 中。

【讨论】:

  • 非常感谢!这就是我一直在寻找的解决方案!我需要调整一些东西,但现在我可以看到一些关于如何进一步开发功能的好例子。
猜你喜欢
  • 2011-07-28
  • 1970-01-01
  • 1970-01-01
  • 2018-01-11
  • 2014-05-21
  • 1970-01-01
  • 2019-07-22
  • 2011-03-21
  • 2010-11-19
相关资源
最近更新 更多