Como eu atribuo a saída de um comando a uma variável sem executar o comando em um subshell?

4

Se eu tiver uma função como esta:

TEST()
{
    if [[ "$1" == "hi" ]]
    then
        exit 1
    fi

    echo "Some text"
}

e se eu executar a função no shell atual com:

TEST "hi"

tudo funciona como esperado. A instrução if na função será verdadeira e o script inteiro será encerrado. Se eu fizer isso, por outro lado:

FUNCTION_OUTPUT=$(TEST "hi")

Para que eu possa capturar o stdout da função em uma variável, a declaração if dentro da função ainda será verdadeira, a "exit 1" ainda será acionada, mas como estamos executando em uma subshell, o script continuará indo.

Em vez de usar VAR_NAME = $ () para executar algo em um subshell e atribuí-lo a uma variável, existe uma maneira de executá-lo no shell atual para que a linha "exit 1" na minha função realmente saia de todo roteiro?

    
por Tal 08.10.2015 / 03:17

4 respostas

3

A atribuição de variáveis é apenas um Comando simples , para que você possa usar o se a condição verificar se o sucesso da função falhou:

if ! FUNCTION_OUTPUT=$(TEST hi); then
  echo Function return non-zero status
  exit 1
fi

# This line never printed
printf '%s\n' "$FUNCTION_OUTPUT"

Se a função tiver sucesso, você terá a variável FUNCTION_OUTPUT com o resultado da função:

if ! FUNCTION_OUTPUT=$(TEST hii); then
  echo Function return non-zero status
  exit 1
fi

# Output content of FUNCTION_OUTPUT
printf '%s\n' "$FUNCTION_OUTPUT"
    
por 08.10.2015 / 04:27
1

Redirecionar o comando para um arquivo e ler o arquivo em uma variável com um arquivo interno, por exemplo, com mapfile .

    
por 08.10.2015 / 03:31
1

Existem várias maneiras de sair de um script.

VAR=$(FUNCTION) || kill -"$(($?&127))" 0

... pode ser um caminho. Ele deve passar para o grupo de processos do shell pai, qualquer que seja o retorno de FUNCTION . Não é realmente desenvolvido, mas você pode facilmente obter o retorno de uma substituição de comando se é isso que você está pedindo. Senão, se você quiser sugestões sobre a atribuição de uma variável, bem, de dentro de uma função atual do shell, você pode fazer como:

fn(){ var=x; }; fn; echo "$var"
x

Se deve ser a saída de algum comando, então você está falando sobre avaliação em camadas. Você realmente precisa confiar nessa saída, ou então você precisa capturar o fluxo inteiro, e nesse caso é melhor ter certeza de quando esperar. Essas coisas geralmente são feitas com pipes - que é como funcionam as substituições de comandos - bem, isso e subcamadas, é claro. Assim como o shell, você precisa read dos dados, como é sugerido em outro lugar.

Eu gosto de usar meu próprio pipe - eu escrevo um pouco de cada vez no buffer do pipe e o leio novamente quando estou pronto.

fn(){ echo hey; read hey; } <> <(:) >&0
fn; echo "$hey"
hey

... Eu acho que devo mencionar que, se você seguir este último exemplo, você deve tomar um cuidado especial não para preencher o buffer. Apenas escreva um pouco de cada vez e leia-o assim que puder. Em praticamente qualquer sistema, você pode contar com um buffer de base de 512 bytes - o que não é muito -, mas eles geralmente são maiores.

Se você não for cuidadoso, então, como o dono de ambas as extremidades daquele tubo, seu shell não receberá nenhum sinal frustrado de quit de qualquer outro processo quando ele travar, e ele ficará preso para sempre. Eu nunca aponto a saída de qualquer comando não-embutido em um desses descritores de arquivo, a menos que eu já tenha bifurcado um processo de leitura para drenar o tubo conforme necessário.

Seu material como aquele que torna o mesmo processo de mensagens difícil - você tem que gerenciá-lo meticulosamente, em perfeita sincronia, e rastrear todos os segmentos separados de uma tarefa simultaneamente. É por isso que os reservatórios são forjados.

    
por 08.10.2015 / 05:07
0

Eu uso:

tmp_fifo=$(mktemp)
mkfifo ${tmp_fifo}
exec 5<>${tmp_fifo}

assign() {
  local var=$1;
  shift
  "$@" >&5
  read ${var} <&5
}

assign myVar echo hola
echo $myVar

rm -f ${tmp_fifo}
    
por 25.12.2016 / 00:15