代码之家  ›  专栏  ›  技术社区  ›  V0ldek

忽略最后一个发送到程序的查询的所有(多行)结果

  •  1
  • V0ldek  · 技术社区  · 7 年前

    我有一个可执行文件,它接受来自stdin的查询并响应它们,直到EOF为止。另外,我有一个输入文件和一个特殊的命令,让我们调用它们 EXEC , FILE CMD 分别。

    我需要做的是:

    • 通过 执行程序 作为输入。
    • 忽略与从中读取的命令相对应的所有输出 文件 ( /dev/null/ )
    • 通过 CMD 作为最后一个命令。
    • 获取最后一个命令的输出并将其保存在变量中。

    执行程序 对于每个查询,其输出可以是多行。

    我知道怎么通过 FILE + CMD 进入 执行程序 :

    echo ${CMD} | cat ${FILE} - | ${EXEC}
    

    但我不知道如何只获取 CMD .

    环顾四周,我发现了以下部分解决方案:

    mkfifo mypipe
    
    (tail -f mypipe) | ${EXEC} &
    
    cat ${FILE} | while read line; do
        echo ${line} > mypipe
    done
    
    echo ${CMD} > mypipe
    

    这允许我重定向输入,但现在输出被打印到屏幕上。我想忽略 执行程序 while 循环并仅获取最后一行的打印内容。

    我尝试了我最初想到的,那就是:

    (tail -f mypipe) | ${EXEC} > somefile &
    

    但它不起作用,文件是空的。

    3 回复  |  直到 7 年前
        1
  •  0
  •   Charles Duffy    7 年前

    这很容易发生种族冲突——我建议在 kill 或者使用一个显式的sigil来确定它何时被接收。也就是说:

    #!/usr/bin/env bash
    
    # route FD 4 to your output routine
    exec 4> >(
      output=; trap 'output=1' USR1
      while IFS= read -r line; do
        [[ $output ]] && printf '%s\n' "$line"
      done
    ); out_pid=$!
    
    # Capture the PID for the process substitution above; note that this requires a very
    # new version of bash (4.4?)
    [[ $out_pid ]] || { echo "ERROR: Your bash version is too old" >&2; exit 1; }
    
    # Run your program in another process substitution, and close the parent's handle on FD 4
    exec 3> >("$EXEC" >&4)  4>&-
    
    # cat your file to FD 3...
    cat "$file" >&3
    
    # UGLY HACK: Wait to let your program finish flushing output from those commands
    sleep 0.1
    
    # notify the subshell writing output to disk that the ignored input is done...
    kill -USR1 "$out_pid"
    
    # UGLY HACK: Wait to let the subprocess actually receive the signal and set output=1
    sleep 0.1
    
    # ...and then write the command for which you actually want content logged.
    echo "command" >&3
    

    在验证此答案时,我将执行以下操作:

    EXEC=stub_function
    stub_function() {
      local count line
      count=0
      while IFS= read -r line; do
        (( ++count ))
        printf '%s: %s\n' "$count" "$line"
      done
    }
    
    cat >file <<EOF
    do-not-log-my-output-1
    do-not-log-my-output-2
    do-not-log-my-output-3
    EOF
    file=file
    
    export -f stub_function
    export file EXEC
    

    输出仅为:

    4: command
    
        2
  •  0
  •   Damon    7 年前

    你可以把它输入一个SED:

    var=$(YOUR COMMAND | sed '$!d')
    

    这只会将最后一行放入变量中

        3
  •  0
  •   Walter A    7 年前

    我认为,您的proram exec做了一些特殊的事情(打开连接或记住状态)。如果不是这样,您可以使用

    ${EXEC} < ${FILE} > /dev/null
    myvar=$(echo ${CMD} | ${EXEC})
    

    或使用普通命令:

    # Do not use (printf "==%s==\n" 1 2 3 ;  printf "oo%soo\n" 4 5 6) | cat
     printf "==%s==\n" 1 2 3 | cat > /dev/null
     myvar=$(printf "oo%soo\n" 4 5 6 | cat)
    

    当您需要为一个进程提供所有输入时,也许您可以考虑一个可以筛选的标记:

    (printf "==%s==\n" 1 2 3 ;  printf "%s\n" "marker"; printf "oo%soo\n" 4 5 6) | cat | sed '1,/marker/ d'
    

    你应该检查一下你的主管可以使用什么。当它运行SQL时,您可能会使用

    (cat ${FILE}; echo 'select "DamonMarker" from dual;' ; echo ${CMD} ) |
       ${EXEC} | sed '1,/DamonMarker/ d'
    

    并将其写在var中

    myvar=$( (cat ${FILE}; echo 'select "DamonMarker" from dual;' ; echo ${CMD} ) |
           ${EXEC} | sed '1,/DamonMarker/ d' )