【问题标题】:GNU parallel sorted stdout and stderrGNU 并行排序标准输出和标准错误
【发布时间】:2016-01-10 03:30:58
【问题描述】:

我一直在使用 GNU 并行,我想保持输出顺序 (--kepp-order),按作业分组 (--grouped),但也使用排序的 stdout 和 stderr。现在,分组选项首先打印 stdout,然后才打印 stderr。

作为一个例子,这两个命令给出相同输出的任何方式?

seq 4 | parallel -j0 'sleep {}; echo -n start{}>&2; sleep {}; echo {}end'

seq 4 | parallel -j0 'sleep {}; echo -n start{}   ; sleep {}; echo {}end'

谢谢,

【问题讨论】:

    标签: gnu-parallel


    【解决方案1】:

    根据对另一个答案的评论,为了保持输出有序,只需将并行的 bash 调用重定向 stderrstdout

    parallel myfunc '2>&1'

    例如,

    parallel -j8 eval \{1} -w1 \{2} '2>&1' ::: "traceroute -a -f9" traceroute6 ::: ordns.he.net one.one.one.one google-public-dns-a.google.com

    【讨论】:

      【解决方案2】:

      如果您仍希望将 stderr 和 stdout 分开,则不能这样做。

      原因是 stderr 和 stdout 使用缓冲输出缓冲到 2 个不同的文件。

      但也许你可以解释一下你需要这个做什么。在这种情况下,可能会有解决方案。

      【讨论】:

      • 我正在尝试并行化几个 bash 命令,因此我将它们全部放在一个 bash 函数中,并从并行调用该函数并将输出存储在日志文件中。到目前为止一切顺利,但有些命令打印到标准输出,而其他命令打印到标准错误!理想情况下,我希望消息按顺序显示,以便我可以浏览日志文件并查看是否有任何问题以及在哪里......
      • 那么如何将记录到 stdout 的命令重定向到 stderr,以便 stderr 包含所有记录信息?或者简单地将所有内容发送到标准输出:parallel myfunc '2>&1' ::: args
      【解决方案3】:

      假设您不必使用 gnu 并行,并且主要要求是并行执行,并保持 stderr 和 stdout 的有序输出;我们可以创建一个允许以下示例用法的解决方案(加上提供返回代码),您将在列表中获得执行结果,其中每个列表元素返回一个包含 3 个字符串的列表:索引为 0=stdout , 1=stderr 和 2=返回码。

      source mapfork.sh
      ArgsMap=("-Pn" "-p" "{}" "{}")
      Args=("80" "google.com" "25" "tutanota.com" "80" "apa bepa")
      declare -a Results=$(mapfork nmap "(${ArgsMap[*]@Q})" "(${Args[*]@Q})")
      

      因此,例如,为了打印第三个目的地(“apa bepa”)的 stderr 结果,您可以这样做:

      declare -a res3="${Results[2]}"
      declare -p res3
      # declare -a res3=([0]=$'Starting Nmap 7.70 ( https://nmap.org ) at 2019-06-21 18:55 CEST\nNmap done: 0 IP addresses (0 hosts up) scanned in 0.09 seconds' [1]=$'Failed to resolve "apa bepa".\nWARNING: No targets were specified, so 0 hosts scanned.' [2]="0")
      printf '%b\n' "${res3[1]}"
      

      mapfork.sh 如下所示。这有点复杂,但它的部分已在其他答案中进行了解释,因此我也不会在这里提供详细信息:

      Capture both stdout and stderr in Bash [duplicate]

      How can I make an array of lists (or similar) in bash?

      #!/bin/bash
      # reference: https://stackoverflow.com/questions/13806626/capture-both-stdout-and-stderr-in-bash
      nullWrap(){
          local -i i; i="$1"
          local myCommand="$2"
          local -a myCommandArgs="$3"
          local myfifo="$4"
          local stderr
          local stdout
          local stdret
          . <(\
          { stderr=$({ stdout=$(eval "$myCommand ${myCommandArgs[*]@Q}"); stdret=$?; } 2>&1 ;\
                     declare -p stdout >&2 ;\
                 declare -p stdret >&2) ;\
            declare -p stderr;\
          } 2>&1)
          local -a Arr=("$stdout" "$stderr" "$stdret")
          printf "${i}:%s\u0000" "(${Arr[*]@Q})" > "$myfifo"
      }
      mapfork(){
          local command
          command="$1"
          local -a CommandArgs="$2"
          local -a Args="$3"
          local -a PipedArr
          local -i i
          local myfifo=$(mktemp /tmp/temp.XXXXXXXX)
          rm "$myfifo"
          mkfifo "$myfifo"
      
          local -a placeHolders=()
          for ((i=0;i<${#CommandArgs[@]};i++)); do
          [[ "${CommandArgs[$i]}" =~ ^\{\}$ ]] && placeHolders+=("$i") ;done
      
          for ((i=0;i<${#Args[@]};i+=0)); do
          # if we have placeholders in CommandArgs we need to take args
          # from Args to replace.
          if [[ ${#placeHolders[@]} -gt 0 ]]; then
              for ii in "${placeHolders[@]}"; do
              CommandArgs["$ii"]="${Args[$i]}"
              i+=1; done; fi
          nullWrap "$i" "$command" "(${CommandArgs[*]@Q})" "$myfifo" &
          done
          for ((i=0;i<${#Args[@]};i+=$(("${#placeHolders[@]}")))) ; do
          local res
          res=$(read -d $'\u0000' -r temp <"$myfifo" && printf '%b' "$temp")
          local -i resI
          resI="${res%%:*}"
          PipedArr[$resI]="${res#*:}"
          done
          # reference: https://stackoverflow.com/questions/41966140/how-can-i-make-an-array-of-lists-or-similar-in-bash
          printf '%s' "(${PipedArr[*]@Q})"
      }
      

      【讨论】:

        猜你喜欢
        • 2012-12-11
        • 1970-01-01
        • 1970-01-01
        • 2011-06-26
        • 2014-07-22
        • 1970-01-01
        • 2014-08-25
        • 1970-01-01
        • 2012-02-23
        相关资源
        最近更新 更多