如何在捕获 stdout 输出的同时修改 bash 函数中的全局变量并返回有效的返回码?

问题描述 投票:0回答:2

在 bash 编程中,我目前面临一个问题,我不仅想修改 bash 函数中的全局变量,还想通过

return
$?
返回正确的返回代码,并且能够分配所有
stdout 
在函数调用函数外部变量期间出现的输出。

虽然这些单独的任务中的每一个(修改全局变量、返回状态代码、将标准输出分配给变量)似乎在 bash 中都是完全可能的(甚至是这些愿望中的两个的组合),但所有三个要求的组合似乎很难(即只是不方便)可能。

这是我准备演示该问题的示例脚本:

#!/bin/bash
#
# This is the required output:
#
# -- cut here --
# RETURN: '2'
# OUTPUT: 'Hello World!'
# GLOBAL_VAR: '3'
# -- cut here --
#

GLOBAL_VAR=0

hello() {
  echo "Hello World!"
  GLOBAL_VAR=3
  return 2
}

# (1) normal bash command substition (subshell)
#     PROBLEM: GLOBAL_VAR is 0 but should be 3
#              (hello is executed in subshell)
#
output=$(hello) ; result=$?

# (2) use 'read' and a reverse pipe
#     PROBLEM: RETURN and GLOBAL_VAR is 0
#              (hello in subshell and read return
#               code returned)
#
#read output < <(hello) ; result=$?

# (3) normal function execution
#     PROBLEM: no catched output!
#
#hello ; result=$?

# (4) using lastpipe + read
#     PROBLEM: GLOBAL_VAR is 0 but should be 3
#              (a pipe generateѕ a subshell?!?!)
#
#shopt -s lastpipe
#hello | read output ; result=${PIPESTATUS[0]}

# (5) ksh-like command substiution
#     PROBLEM: Works, but ksh-syntax 
#              -> doesn't work in bash!
#
#output=${ hello; } ; result=$?

# (6) using a temp file to catch output of hello()
#     WORKS, but ugly due to tmpfile and 2xsubshell use!
#
#tmp=$(mktemp)
#hello >${tmp} ; result=$?
#output=$(cat ${tmp})
#rm -f ${tmp}

###################################
# OUTPUT stuff

# this should output "2"
echo "RESULT: '${result}'"

# this should output "Hello World!"
echo "OUTPUT: '$output'"

# this should output "3"
echo "GLOBAL_VAR: '$GLOBAL_VAR'"

在此脚本中,我添加了一个函数

hello()
,它应返回状态代码 2,将全局变量
GLOBAL_VAR
设置为 3 并输出“Hello World!”到
stdout
。 除了这个函数之外,我还添加了 6 个潜在的解决方案来调用这个
hello()
函数,以准确实现我需要的输出(显示在 bash 脚本代码的顶部)。

通过注释/注释这6种不同的函数调用方式,你会发现只有解决方案(6)可以满足我调用函数的所有要求。

特别有趣的是,解决方案编号 (5) 显示了 ksh 语法,其工作方式与我要求此函数工作的方式完全相同。因此,使用

ksh
调用此脚本会输出所有变量及其所需值。当然,bash 不支持此解决方案(使用
${ cmd; }
进行命令替换)。但是,我肯定需要一个 bash 解决方案作为主脚本,我需要我的解决方案是一个仅 bash 的脚本,我无法移植到 ksh。

当然,解决方案(6)也满足我的要求,它需要将

hello()
的输出放入临时文件中,然后再次读取它。就性能而言(需要多个子 shell、临时文件管理),这对我来说不是真正的解决方案。

所以现在问题来了,bash 中是否有任何其他潜在的解决方案可以满足我的要求,以便上面的脚本输出正是我想要的,从而结合了我的所有三个要求?!?

bash shell unix command-line substitution
2个回答
1
投票

从问题中尚不清楚为什么不能简单地重写函数以使其表现不同。 如果实在改不了功能,可以改一下bash:

#!/bin/bash

GLOBAL_VAR=0

hello() {
  echo "Hello World!" 
  GLOBAL_VAR=3
  return 2
}

echo ()  { output=$*; }
hello
result=$?
unset -f echo

# this should output "2"
echo "RESULT: '$result'"

# this should output "Hello World!"
echo "OUTPUT: '$output'"

# this should output "3"
echo "GLOBAL_VAR: '$GLOBAL_VAR'"

输出符合预期。


0
投票

我最终使用了“写入临时文件”方法。如果你做出一些假设,它就可以变得理智:如果你在开始时设置一个“暂存空间”,并且从不运行并行调用,它可以像这样简单:

#!/bin/bash

# One time setup:
SCRATCH=/tmp/my-script.$$ # prevent conflicts by using PID
trap "rm -f $SCRATCH" EXIT # prevent conflicts by cleaning up after PID is done

# ... some other stuff ...

hello > $SCRATCH; result=$?; read output < $SCRATCH

# ... do more stuff with $result and $output

# ... call hello() as many times as you want 
© www.soinside.com 2019 - 2024. All rights reserved.