PID фоновой функции F в командах, вызываемых в подshellх внутри F

Когда foo запускается в фоновом режиме, BASHPID для foo ( bashpid_of_foo ) недоступен внутри тел от bar_1 до bar_n через $BASHPID , так как они вызываются с помощью функции подстановки команд в bash :

 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 через переменные среды bashpid_of_foo или файлы внешнего диска?

Под элегантностью я имею в виду возможность поддерживать интерфейсы и тела функций bar_* чистоте, полагаясь только на предоставляемые bash функции. (Например, BASHPID – это функция bash .)

Если я попытаюсь переопределить значение BASHPID , как это,

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

… он (справедливо) жалуется на BASHPID что BASHPID является переменной только для BASHPID .

РЕДАКТИРОВАТЬ: (1) Добавлено определение bar_1 выше. (2) Добавлен второй вызов foo на заднем плане. Каждый вызов foo должен поддерживать свой собственный файл журнала, так как запись в общий файл может привести к искаженному содержимому.

ПРИМЕЧАНИЕ. Что бы ни происходило в журнале в контексте времени выполнения foo , я хочу, чтобы оно попадало в файл журнала, /path/to/log.$BASHPID foo , /path/to/log.$BASHPID БЕЗ передавая имя этого файла журнала или даже PID foo . foo может иметь несколько экземпляров, работающих в фоновом режиме.

 #!/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 из foo в bar , очевидно, состоит в том, чтобы передать его в качестве аргумента командной строки и получить его с local bashpid="$1" в bar или чем-то подобным, но вы говорите, что не хотите этого делать.

ПРИМЕЧАНИЕ. Что касается ваших общих вопросов о $BASHPID , это только для $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_1 в сценарий оболочки:

 $ 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 правильно экспортируется в подоболочки:

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

Мы должны использовать export здесь, а не только local потому что иначе переменные среды не будут экспортированы ни в какие дочерние элементы. Подоболочки – это детские снаряды.

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