后台函数 F 的 PID,在 F 内的子 shell 中调用的命令中

后台函数 F 的 PID,在 F 内的子 shell 中调用的命令中

foo在后台运行时,BASHPIDof foo( ) 在vi bashpid_of_foo​​a 体内不可用bar_1,因为它们是通过 的命令替换功能调用的:bar_n$BASHPIDbash

function foo() {
    local bashpid_of_foo=$BASHPID
    local output

    # desired to be shared by all Command Substitutions
    # in the body of this function.
    local log=/path/to/log.$BASHPID

    ... >> $log

    output=$(bar_1 ...)
      ...
    output=$(bar_n ...)
}

function bar_1() {
   # log only specific (and NOT all) messages
   # to the shared log file of the invoking thread.
    ... >> /path/to/log.$BASHPID
}

foo &
foo &

问题:是否有一种优雅的方法可以解决上述限制,而无需bashpid_of_foo通过临时环境变量或外部磁盘文件传递?

经过优雅的,我的意思是,能够bar_*通过仅依赖 bash 提供的功能来保持函数的接口和主体的干净。 (例如,BASHPID是一个bash功能。)

如果我尝试像这样覆盖 的值BASHPID

out_1=$(BASHPID=$BASHPID bar_1 ...)

...它(正确地)抱怨BASHPID是一个只读变量。

编辑:(1) 增加了上述定义bar_1。 (2)foo在后台添加了第二次调用。每个foo调用都需要维护自己的日志文件,因为写入公共文件可能会导致内容乱码。

笔记:无论运行时上下文中发生什么日志记录foo,我都希望它进入foo特定的日志文件,/path/to/log.$BASHPID 没有传递该日志文件的名称,甚至foo.foo可以有多个实例在后台运行。

答案1

#!/bin/bash

bar () {
    # bashpid is set in our environment from the calling function
    printf 'bar BASHPID = %d, bar bashpid = %d\n' "$BASHPID" "$bashpid"

    # in your case, you would have...

    local logfile="/some/path/to/log.$bashpid"

    # etc.
}

foo () {
    local bashpid="$BASHPID"
    local message

    local logfile="/some/path/to/log.$BASHPID"

    message=$( bashpid="$bashpid" bar ); printf 'Message from bar: %s\n' "$message"
    message=$( bashpid="$bashpid" bar ); printf 'Message from bar: %s\n' "$message"
    message=$( bashpid="$bashpid" bar ); printf 'Message from bar: %s\n' "$message"
    message=$( bashpid="$bashpid" bar ); printf 'Message from bar: %s\n' "$message"
}

foo &
foo &
foo &

wait

运行示例:

$ bash script.sh
Message from bar: bar BASHPID = 71979, bar bashpid = 18461
Message from bar: bar BASHPID = 7420, bar bashpid = 71036
Message from bar: bar BASHPID = 6109, bar bashpid = 18461
Message from bar: bar BASHPID = 27868, bar bashpid = 71036
Message from bar: bar BASHPID = 44547, bar bashpid = 60086
Message from bar: bar BASHPID = 69310, bar bashpid = 71036
Message from bar: bar BASHPID = 37649, bar bashpid = 60086
Message from bar: bar BASHPID = 15999, bar bashpid = 71036
Message from bar: bar BASHPID = 81520, bar bashpid = 18461
Message from bar: bar BASHPID = 92568, bar bashpid = 60086
Message from bar: bar BASHPID = 72438, bar bashpid = 18461
Message from bar: bar BASHPID = 15094, bar bashpid = 60086

foo对于脚本主要部分中的每次调用,bar将进行四次调用并生成四行输出。正如您所看到的,只有三个唯一的bashpid数字,每个数字都来自一次foo调用。

另一种从 传递到 的方法$bashpid显然foobar将其作为命令行参数传递并使用local bashpid="$1"inbar或类似的东西接收它,但你说你不想这样做。

答案2

笔记: 关于您的一般问题$BASHPID,这是只读的,您无法操纵它。这是设计使然。

我的一般建议是,当您使用像这样的 Bash 脚本达到复杂程度时,就应该将其转移到 Python、Ruby 等。


你的例子

我想我不明白你的问题是什么,这对我有用:

$ cat subby.bash
#!/bin/bash

function foo() {
    local bashpid_of_foo=$BASHPID
    local output=blipblop

    echo "foo: $bashpid_of_foo"
    echo "foo: $output"
    out_1=$(echo $bashpid_of_foo)
    out_n=$(echo $output)
    echo "out_1: $out_1"
    echo "out_n: $out_n"
}

foo &


$ ./subby.bash
foo: 4900
foo: blipblop
out_1: 4900
out_n: blipblop

增加出口

如果我们通过编写bar_1shell 脚本来改变这一点:

$ cat bar_1
#!/bin/bash

echo "from bar_1: $bashpid_of_foo"

并像这样更改原始脚本:

#!/bin/bash

function foo() {
    export bashpid_of_foo=$BASHPID
    local output=blipblop

    echo "foo: $bashpid_of_foo"
    echo "foo: $output"
    out_1=$(echo $bashpid_of_foo)
    out_2=$(./bar_1)
    out_n=$(echo $output)
    echo "out_1: $out_1"
    echo "out_2: $out_2"
    echo "out_n: $out_n"
}

foo &

我们可以看到已$bashpid_of_foo正确导出到子 shell:

$ ./subby.bash
foo: 5014
foo: blipblop
out_1: 5014
out_2: from bar_1: 5014
out_n: blipblop

我们需要export在这里使用 an 而不仅仅是 a,local因为否则环境变量将不会导出到任何子级。这里的子 shell 是子 shell。

$ help export
...
   Marks each NAME for automatic export to the environment of subsequently
    executed commands.  If VALUE is supplied, assign VALUE before exporting.

相关内容