É possível manter o último comando exit status ( $?
) inalterado após um teste?
Por exemplo, eu gostaria de fazer:
command -p sudo ...
[ $? -ne 1 ] && exit $?
O último exit $?
deve retornar o status de saída do sudo, mas sempre retorna 0
(o código de saída do teste).
É possível fazer isso sem uma variável temporária?
Outro exemplo para esclarecer mais:
spd-say "$@"
[ $? -ne 127 ] && exit $?
Nesse caso, quero sair apenas se o primeiro comando for encontrado (código de saída! = 127
). E eu quero sair com o spd-say
código de saída real (pode não ser
0
).
EDIT: Eu esqueci de mencionar que eu prefiro uma solução de reclamação POSIX para melhor portabilidade.
Eu uso essa construção em scripts onde eu quero fornecer alternativas para o mesmo comando. Por exemplo, veja meu script crc32 .
O problema com variáveis temporárias é que elas podem sombrear outras variáveis e para evitar que você precise usar nomes longos, o que não é bom para a legibilidade do código.
fonte
if ! command -p sudo; then exit; fi
que teria os mesmos resultados para o seu exemplo.[ $? -ne 127 ] && exit $?
)sudo
comando for bem-sucedido (ou seja, sesudo
sair com o status 0). Mas, no seu código, o script continua em execução (não sai) sesudo
for bemcommand
esudo
na verdade não são . É isso o que quero dizer com sair apenas se o primeiro comando for encontrado (código de saída! = 127) e for um retorno especificado paracommand
quando o comando que ele chama não for encontrado. Eu acho que o problema é que invocarsudo
como parte do teste permitesudo
esmagar o retornocommand
em primeiro lugar e assim distorcer o teste.Respostas:
$_
vai trabalhar em (pelo menos) interativodash
,bash
,zsh
,ksh
(embora , aparentemente, não em uma declaração condicional, conforme solicitado) emksh
conchas. Desses - que eu saiba - apenasbash
ezsh
também o preencherá em um shell com script. Não é um parâmetro POSIX - mas é bastante portátil para qualquer shell moderno e interativo.Para uma solução mais portátil, você pode:
O que basicamente permite expandir o valor inicial para
$?
o final do script antes mesmo de testar seu valor.Mas de qualquer maneira, já que você parece estar testando se o comando
sudo
pode ou não ser encontrado na cadeia de-p
caminho portátil incorporada do shellcommand
, eu acho que você poderia abordá-lo um pouco mais diretamente. Além disso, só para esclarecer,command
não testará a localização de nenhum argumento parasudo
- por isso é apenassudo
- e nada que ele invoque - o que é relevante para esse valor de retorno.De qualquer forma, se é isso que você está tentando fazer:
... funcionaria muito bem como um teste sem chance de erros no comando
sudo
executado retornando de maneira que possa distorcer os resultados do seu teste.fonte
Existem várias opções para lidar com o status de saída de forma confiável e sem custos indiretos, dependendo dos requisitos reais.
Você pode salvar o status de saída usando uma variável:
Você pode verificar diretamente o sucesso ou o fracasso:
Ou use uma
case
construção para diferenciar o status de saída:com o caso especial solicitado na pergunta:
Todas essas opções têm a vantagem de estar em conformidade com o padrão POSIX.
(Nota: Para ilustração, usei os
echo
comandos acima; substitua porexit
instruções apropriadas para corresponder à função solicitada.)fonte
("$(get_errnos)")
é uma adição artificial de uma substituição de comando, na qual são solicitadas comparações com códigos de erro reais na pergunta, 2.) No padrão, é claro o que muda$?
(e, portanto, o que não muda) e 3.) não há efeitos colaterais com essa construção (a menos que, como você fez, você os introduz desnecessariamente). - OTOH, como você se importa, a outra resposta que você prefere é claramente fora do padrão.$(get_errnos)
código artificial a outras soluções (( exit 42 ); test "$(get_errnos)" -ne $? && echo $_
), elas também não funcionarão. (Você preferiu colocar minha solução padrão em descrédito incorreto, não os outros hackes não padrão .) - É claro que você pode adicionar código arbitrário a qualquer resposta e estragá-lo. - E WRT para a mudança de$?
; só porque você não consegue encontrá-lo, não significa que não seja verdade. (Eu já forneci em nossas discussões até as palavras-chave para pesquisar no POSIX.) #zsh
(mencionado apenas sozinho; depois você adicionou tambémdash
) que acho que deve ser um bug, já que ocase
status de saída e a configuração de$?
parecem bem definidos no POSIX. - E também aqui, novamente, você aplica padrões duplos; o outro hack, por exemplo, não é padrão, nem funciona de maneira confiável em outros shells padrão (por exemplo, não emksh
). - Minhas propostas são padrão e funcionambash
(principalmente usadas no Linux) eksh
(o shell predominante nos Unixes comerciais).Use
$_
, que se expande para o último argumento do comando anterior.fonte
$?
e$_
referências. IMHO, é melhor seguir um método consistente que funcione em outros casos (e também pode ajudar na legibilidade do código).case
padrões , o único lugar que importaria na teoria (mas não na questão dada), é um caso construído. - De qualquer forma, sua substituição de comando do shell propagaria o resultado do comando incorporado, normalmente outras expansões não afetarão o estado de retorno de qualquer maneira, se não houver comandos envolvidos que possam criar erros (x=${a!b}
casos mentais , mas irrelevantes aqui). - O que você quer dizer com "comando sem nome do comando" ?Você pode definir (e usar) uma função shell:
Então
Indiscutivelmente, isso é "trapaça", uma vez que faz uma cópia
$?
nacheck_exit_status
lista de argumentos.Isso pode parecer um pouco estranho, e é. (Isso às vezes acontece quando você impõe restrições arbitrárias aos problemas.) Isso pode parecer inflexível, mas não é. Você pode tornar
check_exit_status
mais complexo, adicionando argumentos que informam quais testes devem ser feitos no valor do status de saída.fonte
Para responder sua pergunta direta, não, não é possível manter-se
$?
inalterado. E esse é um daqueles casos em que suspeito que você esteja se concentrando no problema errado. Uma variável temporária é a maneira padrão e preferida de obter o efeito que você está procurando. É tão padrão que eu sugeriria abandonar (ou repensar) qualquer que seja o motivo que você acha que tem por não querer usar um; Duvido muito que valha a complexidade extra adicionada por qualquer outro método.Se você está apenas perguntando por simples curiosidade, a resposta é não.
fonte
$?
ou algo assim?Aqui está meu snippet de código para manter um status de saída anterior sem sair do script / shell atual
fonte