Bash 中的条件管道(自定义脚本)

Bash 中的条件管道(自定义脚本)

我如何通过管道传输命令,并在脚本内部决定是否应该中断管道。

它类似于这个问题。但awk我更愿意使用自己的脚本:

check_ip | update_bind9

check_ip应该找到外部 IP(curl -s ifconfig.co)并将其与存储在文件中的 IP 进行比较(~/.ip)。

以下是主要问题:

如果 IP 已更改,check_ip则应通过管道传递 IP。如果没有,则应断开管道。

这是否check_ip会破坏管道,或者update_bind9如果没有使用 IP 调用则会忽略调用?

我做了一些测试,调用:check_ip | echo "ok"

我试过exit 0exit 1return truereturn false试过set -e。没有成功。

答案1

管道的所有组件同时开始– 无论第一个命令中发生什么,第二个命令始终都会启动。

因此,第二个命令需要处理空的标准输入。


但我首先要说的是,管道并不是一个好的选择。

(也许你把|(管道)和||(布尔或)混淆了?后者通常用作 if/then 的较短替代,例如,x || y仅当 x 失败时才会调用 y - 类似地,x && y仅当 x 成功时才会调用 y。)

通常,您应该使用 if/then 块。例如,如果check_ip地址不同,if 本身返回 0(成功),如果地址相同,则返回 1(失败),如下所示:

if addr=$(check_ip); then
    echo "$addr" | update_bind9
fi

或者,如果 update_bind9 可以自行确定地址(无需读取 stdin),则会如下所示:

if check_ip_needs_updating; then
    update_bind9
fi

答案2

其他答案很好。但是如果你真的需要有条件地进行管道传输,那么你可能会发现ifne有用:

ifne当且仅当标准输入不为空时,才运行以下命令。

在你的情况下它将像check_ip | ifne update_bind9

很可能ifne默认情况下未安装在您的 Linux 中。在我的 Debian 10 中,它在moreutils包中。有人可能会认为额外的工具完全是多余的,因为我们可以将输出存储check_ip在变量中并有条件地重用它,就像提到的答案中一样:

if addr=$(check_ip); then
    echo "$addr" | update_bind9
fi

条件可能是[ -n "$addr" ],无论如何;重要的是我们使用变量。像上面的代码可能会解决您的问题,但通常至少存在三个问题。假设command1 | command2而不是check_ip | update_bind9。解决方案概括为:

if foo=$(command1); then
    echo "$foo" | command2
fi

进而:

  1. foo=$(command1)将从 的输出中删除所有尾随的换行符command1。然后echo "$foo"(或printf … "$foo") 将添加一个换行符(或分别添加固定数量的换行符)。因此command2可能无法从 获得准确的输出command1

  2. command1可能会产生包含 NUL 字符的输出。Bash 无法将 NUL 存储在变量中(大多数 shell 不能;zsh 可以)。如果出现 NUL,则command2不会从 获得准确的输出command1

  3. command1可能会产生巨大甚至是无穷无尽的流,因此将其存储在变量中可能无法实现。

使用文件而不是变量可以解决除最后一个问题之外的所有问题。command1 | ifne command2对所有三个问题均无影响。

相关内容