Eu gostaria de implementar uma função no Bash que aumenta (e retorna) uma contagem a cada chamada. Infelizmente, isso não parece trivial, pois estou invocando a função dentro de um subshell e, consequentemente, não pode modificar as variáveis do shell pai.
Aqui está a minha tentativa:
PS_COUNT=0
ps_count_inc() {
let PS_COUNT=PS_COUNT+1
echo $PS_COUNT
}
ps_count_reset() {
let PS_COUNT=0
}
Isso seria usado da seguinte maneira (e, portanto, minha necessidade de invocar as funções de um subshell):
PS1='$(ps_count_reset)> '
PS2='$(ps_count_inc) '
Dessa forma, eu teria um prompt de várias linhas numerado:
> echo 'this
1 is
2 a
3 test'
Fofa. Mas, devido à limitação mencionada acima, não funciona.
Uma solução não útil seria gravar a contagem em um arquivo em vez de em uma variável. No entanto, isso criaria um conflito entre várias sessões em execução simultânea. Eu poderia acrescentar o ID do processo do shell ao nome do arquivo, é claro. Mas espero que exista uma solução melhor que não atrapalhe meu sistema com muitos arquivos.
man 1 mktemp
.Respostas:
Para obter a mesma saída que você anotou na sua pergunta, tudo o que é necessário é o seguinte:
Você não precisa se contorcer. Essas duas linhas farão tudo em qualquer shell que pretenda algo próximo à compatibilidade com POSIX.
Mas gostei disso. E eu queria demonstrar os fundamentos do que torna esse trabalho um pouco melhor. Então eu editei isso um pouco. Fiquei preso
/tmp
por agora, mas acho que vou mantê-lo para mim também. Está aqui:PROMPT SCRIPT:
Nota: tendo aprendido recentemente sobre yash , eu o construí ontem. Por qualquer motivo, ele não imprime o primeiro byte de cada argumento com a
%c
string - embora os documentos sejam específicos sobre extensões de caracteres largos para esse formato e, portanto, talvez relacionados - mas funciona bem com%.1s
Essa é a coisa toda. Há duas coisas principais acontecendo lá em cima. E é assim que se parece:
ANÁLISE
$PWD
Mas e quanto ao aumento?
E é graças ao POSIX especificado
${parameter} $((expansion))
que mantém essas definições no shell atual sem exigir que as definamos em um subshell separado, independentemente de onde as avaliamos. E é por isso que funciona emdash
esh
tão bem quanto embash
ezsh
. Não usamos escapes dependentes do shell / terminal e permitimos que as variáveis se testem. É isso que torna o código portátil rápido.O resto é bastante simples - basta incrementar nosso contador para cada vez que
$PS2
é avaliado até$PS1
que o redefina novamente. Como isso:Então agora eu posso:
DASH DEMO
SH DEMO
Funciona da mesma forma em
bash
oush
:Como eu disse acima, o principal problema é que você precisa considerar onde faz o cálculo. Você não obtém o estado no shell pai - portanto, não computa lá. Você obtém o estado no subshell - e é aí que você calcula. Mas você faz a definição no shell pai.
fonte
PS2
? Esta é a parte complicada. Não acho que sua solução possa ser aplicada aqui. Se você pensa o contrário, por favor, mostre-me como.PS1
ePS2
são variáveis especiais no shell que são impressas como prompt de comando (tente definindoPS1
um valor diferente em uma nova janela do shell), elas são usadas de maneira muito diferente do seu código. Aqui estão mais algumas informações sobre seu uso: linuxconfig.org/bash-prompt-basics #echo 'this
em um prompt e explique como atualizar o valor dePS2
antes de digitar a aspas simples de fechamento.Com essa abordagem (função em execução em um subshell), você não poderá atualizar o estado do processo mestre do shell sem passar por contorções. Em vez disso, organize a função para executar no processo mestre.
O valor da
PROMPT_COMMAND
variável é interpretado como um comando que é executado antes de imprimir oPS1
prompt.Pois
PS2
não há nada comparável. Mas você pode usar um truque: como tudo o que você quer fazer é uma operação aritmética, você pode usar a expansão aritmética, que não envolve um subshell.O resultado da computação aritmética termina no prompt. Se você deseja ocultá-lo, pode passá-lo como um subscrito de matriz que não existe.
fonte
É um pouco intensivo de E / S, mas você precisará usar um arquivo temporário para armazenar o valor da contagem.
Se você estiver preocupado com a necessidade de um arquivo separado por sessão do shell (o que parece ser uma preocupação menor; você realmente digitará comandos de várias linhas em dois shells diferentes ao mesmo tempo?), Você deve
mktemp
criar um novo arquivo para cada usar.fonte
Você não pode usar uma variável de shell dessa maneira e já entende o porquê. Um subshell herda variáveis exatamente da mesma maneira que um processo herda seu ambiente: quaisquer alterações feitas se aplicam apenas a ele e a seus filhos e não a nenhum processo ancestral.
Conforme outras respostas, a coisa mais fácil a fazer é esconder esses dados em um arquivo.
Etc.
fonte
mktemp
).PS2
é expandido pelo shell. Você não tem a oportunidade de atualizar o valor de uma variável no shell pai naquele momento.Para referência, aqui está minha solução usando arquivos temporários, que são exclusivos por processo de shell, e excluídos o mais rápido possível (para evitar confusão, conforme mencionado na pergunta):
fonte