Por que as tarefas 'jobs' e 'dirs' executam em comando as tarefas de subsituição, substituição de processo, pipeline e em background da mesma forma que no shell original?

1

Se eu estiver correto, as tarefas de substituição de comandos, de substituição de processos, de pipeline e de segundo plano executam os comandos especificados em si mesmos em um subshell que não está no shell original.

Mas quando os comandos são jobs ou dirs , eles saem exatamente como quando são executados diretamente no shell original:

echo $( jobs )

cat <(jobs)

jobs | less

echo $( dirs )

cat <(dirs)

dirs | less

dirs &

Por que isso? É porque os subshells herdam os jobs e dirs stack do shell original, ou porque jobs e dirs são executados no shell original em vez das subshells?

Mas

jobs &

não produz nada. Por que é diferente dos outros comandos? Obrigado.

Relacionadas A origem de um script em subshells ainda permite que os comandos no script acessem o estado do shell original?

    
por Tim 28.07.2018 / 05:22

1 resposta

2

A primeira parte desta resposta é que jobs e dirs são built-ins, então tipicamente o bash apenas os executa diretamente ao invés de invocar um subshell.

Isso é verdade para os casos em que há canais ou substituição de comando ( $(jobs) ) ou substituição de processo ( <(jobs) ).

Este não é realmente o caso para executar o comando em segundo plano ( jobs & ) ou solicitar explicitamente uma subshell (com ( jobs ) .)

Isso explica a última parte da sua pergunta. Quando você executa jobs em um subshell, ele realmente mostra os jobs para o subshell em si.

Aqui está uma boa demonstração desse conceito:

$ sleep 1001 &
[1] 15927
$ sleep 1002 &
[2] 15940
$ jobs
[1]-  Running                 sleep 1001 &
[2]+  Running                 sleep 1002 &
$ ( sleep 1003 & jobs )
[1]+  Running                 sleep 1003 &
$ jobs
[1]-  Running                 sleep 1001 &
[2]+  Running                 sleep 1002 &

Você verá que o caso em que jobs está sendo executado em um subshell, apenas os jobs desse subshell (neste caso sleep 1003 ) serão exibidos.

Agora, para encerrar, precisamos abordar a parte intermediária da pergunta, e é por isso que dirs & (que de fato é executado em um subshell, assim como ( dirs ) ) ainda mostrará os diretórios salvos no pushd pilha.

Acontece que isso ocorre porque o shell exporta a lista de diretórios na variável de matriz especial DIRSTACK , que é então herdada por subshells. (Você pode ler mais sobre DIRSTACK aqui .)

Uma maneira de demonstrar como isso funciona é usar pushd no subshell e ver como isso não afeta a pilha de diretórios do shell original:

$ dirs
~
$ pushd ~/tmp
~/tmp ~
$ ( dirs; pushd / >/dev/null; dirs )
~/tmp ~
/ ~/tmp ~
$ dirs
~/tmp ~

Acredito que deve abordar todos os itens que você perguntou.

UPDATE : o bash tem uma disposição especial para tornar jobs | less work, tendo o comando jobs executado no shell atual (que não é o caso de outros built-ins).

O código tem uma verificação que é armazenada em uma variável jobs_hack , que é posteriormente verificada para torná-lo executado sem criar um sub-shell e permitir a saída de jobs para outro comando.

Veja aqui para a parte relevante do código-fonte que implementa isso. (A partir do ano 4.4)

    
por 28.07.2018 / 06:24

Tags