【问题标题】:bash intercepting error and stop in pipelinebash 拦截错误并在管道中停止
【发布时间】:2022-09-23 02:53:14
【问题描述】:

我一直在尝试不同的事情但没有成功

所以这就是我想要实现的目标

set -o pipefail
dump \"$@\" \"$db\" | compress | store \"single\" \"$(backupName \"$db\")\"

# I would want something that behaves a bit like this
# meaning if it dump fails, don\'t store
dump \"$@\" \"$db\" && {
  #migicGetStdout | compress | store \"single\" \"$(backupName \"$db\")\"
} || {
  echo failed
}

但它会在转储失败时创建一个空文件

我迷失了管道

我尝试过类似的事情

set -e
set -o pipefail

dump \"${dumpCommonArgs[@]}\" \"${dumpDbArgs[@]}\" \"$@\" \"$db\" > >(compress | store \"single\" \"$(backupName \"$db\")\")

# or

( compress | store \"single\" \"$(backupName \"$db\")\" ) < <(dump \"$@\" \"$db\") || return 2

# or 

## this way compress get the global $@ ... I don\'t understand that either
store \"single\" \"$(backupName \"$db\")\" < <(dump \"${dumpCommonArgs[@]}\" \"${dumpDbArgs[@]}\" \"$@\" \"$db\") > >(compress)


# there would be an easy one
dataToStore=$(dump \"$@\" \"$db\")
rc=$?
# but this means dump is stored in memory before saving... not the best deal as mysql already needs a lot of ram to run a dump

store 函数仍然被调用!

所以似乎我错过了一些东西。

谢谢你的协助

  • 管道的所有部分同时运行.所以你不能有条件地开始后面的,这取决于之前的进展:他们全部同时开始。
  • 当然,如果您转储到文件而不是标准输出,您可以按照您的要求进行操作。
  • 也可以确保dump开始转储数据并仅在写入至少一行时才启动其他部分;但如果那是您想要的,请更新问题以使其清楚。
  • @CharlesDuffy 看起来有人已经建议对 1 行分钟进行测试......任何解决方案都是好的,只要它在开始写入之前不将所有转储存储在 ram 中。

标签: bash pipeline


【解决方案1】:

您必须暂时存储dump 的输出;带有变量的示例:

if out=$(dump "$@" "$db")
then
    printf '%s\n' "$out" |
    compress |
    store "single" "$(backupName "$db")"
else
    echo failed 1>&2
    exit 1
fi

或测试标准输出是否为空(失败时是否没有输出):

dump "$@" "$db" | {
    IFS='' read -r line

    [ -n "${line:+_}" ] || { echo failed 1>&2; exit 1; }

    { printf '%s\n' "$line"; cat; } |
    compress |
    store "single" "$(backupName "$db")"
}

【讨论】:

  • 感谢您的回复。您的第一个脚本是简单的解决方案out="$(dump ...)",但它会首先将所有转储存储在 ram 中。第二个第二个怎么样,它会在每行输入时转储行吗?或者该过程是否等待所有内容在$lines 中堆积,然后再传递到标准输出?如果没有,是否可以改进这样做。如果它太复杂,那么我将删除存储的文件if $? != 0,但我想避免那种“黑客”
  • @AntonyGibbs 第二种解决方案仅读取变量中的第一行,然后根据其值决定 exitcat
  • 我终于明白了printf '%s\n' "$line"; cat; 的含义... @Fravadiba 谢谢:)
【解决方案2】:

基于@Fravadona的回答,我最终编写了一个更通用的函数,并认为分享它也会很好。

set -o pipefail

##
# usage
# cmd1 | onEmptyReturn 2 cmd2 args
# to output direct to file use cat
# cmd1 | onEmptyReturn 2 cat > 'file'
#
# if cmd1 output is empty, cmd2 won't be executed and will return code 2
# otherwise it'll return status code of cmd2 (assuming we have 'set -o pipefail')
#
# arg1: returned status on empty - optional default to 1
onEmptyReturn() {
  local emptyRc=1

  local re='^[0-9]+$'
  [[ ${1-} =~ $re ]] && { emptyRc=$1; shift; }

  IFS='' read -r line

  [ -n "${line:+_}" ] || { echo "Error: stdin is empty." >&2; return $emptyRc; }

  { printf '%s\n' "$line"; cat; } | "$@"

  return $?
}

【讨论】:

    猜你喜欢
    • 2018-09-07
    • 1970-01-01
    • 2022-10-15
    • 2018-11-02
    • 2014-10-17
    • 2013-04-07
    • 2016-05-13
    • 1970-01-01
    • 2019-06-29
    相关资源
    最近更新 更多