Como truncar a atribuição de variável bash sem fechar o pipe

Como truncar a atribuição de variável bash sem fechar o pipe

Estou procurando uma maneira de limitar a quantidade de dados armazenados em uma variável Bash que é inicializada a partir da saída de um subprocesso.

O problema com esta solução potencial é que ela armazena toda a saída antes de truncá-la.

#!/bin/bash

COMMAND_TO_RUN="du /"

OUT_DATA=$($COMMAND_TO_RUN)
OUT_RESULT=$?

if [[ $OUT_RESULT -ne 0 ]]; then
    echo "${OUT_DATA:0:10000}" | head mail -s "Command failed" [email protected]
fi

A alternativa OUT_DATA=$($COMMAND_TO_RUN | head -c 10000)cancela o comando quando os primeiros 10k de saída são lidos e preciso que o comando seja executado até a conclusão para capturar seu estado de saída.

Posso fazer isso facilmente python, mas espero uma bashúnica solução. E também sem recorrer à gravação em disco.

Responder1

Com uma função. Para facilitar a leitura, o exemplo abaixo codifica o comando e tal.

truncated_du() {
   du / | { head -c 10000; cat >/dev/null; }
   return "${PIPESTATUS[0]}"
}

out_data="$(truncated_du)"
out_result="$?"

headpassa no máximo a quantidade desejada de dados para o stdout da função. Se houver mais dados, catirá descartá-los sem interromper du. O status de saída de dué recuperado do PIPESTATUSarray e retornado pela função.

Nota: minhas variáveis ​​usam lower case; veresta resposta.


Sem uma função a mesma solução fica assim:

out_data="$(
   du / | { head -c 10000; cat >/dev/null; }
   exit "${PIPESTATUS[0]}"
)"
out_result="$?"

IMO é um pouco menos legível dessa forma.

Responder2

Isso limita a quantidade que você captura, mas presumo que ele saia com reado status de saída (não sei se para, para o comando como headfaria porque o status de saída não é respeitado: `

IFS= read -r -d '' -n $chars_to_capture foo < <($command)

Parece permitir que o comando seja executado até a conclusão, mas você não obtém o status de saída do comando, obtém reado status de saída, o que não é útil.

Um exemplo

$ IFS= read -r -d '' -n 19 foo < <(seq 50; touch somefile; exit 42); echo "exit=$?"; ls -l somefile
exit=0
-rw-r--r-- 1 glennjackman staff 0 Jul 22 22:04 somefile

Presumo que o fato de o arquivo ser tocado significa que o comando não será interrompido após a captura do número solicitado de caracteres.

Talvez você possa escrever o status de saída em um arquivo no subshell:

IFS= read -r -d '' -n 10000 out_data < <( $command_to_run; echo $? > statusfile )
if [[ -f statusfile ]] && [[ "$(<statusfile)" != "0" ]]; then
    printf "%s\n" "$out_data" | head mail -s "Command failed" [email protected]
    rm statusfile
fi

informação relacionada