在 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:
#!/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'"
输出符合预期。
我最终使用了“写入临时文件”方法。如果你做出一些假设,它就可以变得理智:如果你在开始时设置一个“暂存空间”,并且从不运行并行调用,它可以像这样简单:
#!/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