Cómo truncar la asignación de variables de bash sin cerrar la tubería

Cómo truncar la asignación de variables de bash sin cerrar la tubería

Estoy buscando una manera de limitar la cantidad de datos almacenados en una variable Bash que se inicializa a partir de la salida de un subproceso.

El problema con esta posible solución es que almacena la salida completa antes de truncarla.

#!/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

La alternativa OUT_DATA=$($COMMAND_TO_RUN | head -c 10000)cancela el comando cuando se leen los primeros 10k de salida y necesito que el comando se ejecute hasta su finalización para capturar su estado de salida.

Puedo hacerlo bastante fácilmente en python, pero espero una bashúnica solución. Y además sin recurrir a la escritura en disco.

Respuesta1

Con una función. Para facilitar la lectura, el siguiente ejemplo codifica el comando y demás.

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

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

headpasa como máximo la cantidad deseada de datos a la salida estándar de la función. Si hay más datos, catlos descartará sin interrumpir du. El estado de salida de duse recupera de la PIPESTATUSmatriz y la función lo devuelve.

Nota: mis variables usan lower case; veresta respuesta.


Sin una función, la misma solución se ve así:

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

En mi opinión, es un poco menos legible de esta manera.

Respuesta2

Esto limita la cantidad que captura, pero supongo que sale con readel estado de salida (no sé si detiene el comando como headlo haría porque no se respeta el estado de salida: `

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

Parece permitir que el comando se ejecute hasta su finalización, pero no obtiene el estado de salida del comando, obtiene readel estado de salida, lo cual no es útil.

Un ejemplo

$ 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

Supongo que el hecho de que se toque el archivo significa que el comando no se interrumpe después de capturar la cantidad solicitada de caracteres.

Quizás podrías escribir el estado de salida en un archivo en el 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

información relacionada