Quando foo
executado em segundo plano, o BASHPID
of foo
( bashpid_of_foo
) não está disponível dentro dos corpos bar_1
para bar_n
via $BASHPID
, pois eles são invocados por meio do recurso de substituição de comando de 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 &
Pergunta: Existe uma maneira elegante de contornar a limitação acima, sem ter que passar bashpid_of_foo
por variáveis de ambiente adhoc ou arquivos de disco externo?
Por elegante , quero dizer, ser capaz de manter as interfaces e os corpos das bar_*
funções limpos confiando apenas nos recursos fornecidos pelo bash. (Por exemplo BASHPID
, é um bash
recurso.)
Se eu tentar substituir o valor de BASHPID
, assim,
out_1=$(BASHPID=$BASHPID bar_1 ...)
... ele (corretamente) reclama de BASHPID
ser uma variável readonly.
EDIT: (1) Adicionada a definição bar_1
acima. (2) Adicionado a 2ª chamada foo
em segundo plano. Cada foo
chamada precisa manter seu próprio arquivo de log, pois gravar em um arquivo comum pode resultar em conteúdo ilegível.
NOTA: Qualquer que seja o log que aconteça no contexto de tempo de execução do foo
, quero que ele vá para o foo
arquivo de log específico, /path/to/log.$BASHPID
SEM passar o nome desse arquivo de log ou mesmo o PID do foo
. foo
pode ter várias instâncias em execução em segundo plano.
OBSERVAÇÃO: em relação às suas perguntas gerais sobre
$BASHPID
, isso é somente leitura e você não pode manipulá-lo. Isso é por design.Normalmente, meu conselho geral é que, quando você chegar ao nível de sofisticação com scripts Bash como esse, é hora de movê-lo para Python, Ruby, o que for.
Seu exemplo
Acho que não vejo qual é o seu problema, isso funciona para mim:
Adição de exportação
Se mudarmos isso transformando
bar_1
em um script de shell:E altere seu script original assim:
Podemos ver que o
$bashpid_of_foo
está sendo exportado corretamente para subshells:Precisamos usar um
export
aqui e não apenas umlocal
porque, caso contrário, as variáveis de ambiente não serão exportadas para nenhum filho. Os subshells são shells filhos aqui.Exemplo de execução:
Para cada chamada de
foo
na parte principal do script, quatro chamadas parabar
serão feitas e quatro linhas de saída serão produzidas. Como você vê, existem apenas trêsbashpid
números únicos, cada um de uma dasfoo
invocações.Outra maneira de passar
$bashpid
defoo
tobar
é obviamente passá-lo como um argumento de linha de comando e recebê-lo comlocal bashpid="$1"
inbar
ou algo semelhante, mas você diz que não quer fazer isso.