Как обрезать присвоение переменной bash, не закрывая канал

Как обрезать присвоение переменной bash, не закрывая канал

Я ищу способ ограничить объем данных, хранящихся в переменной Bash, которая инициализируется из выходных данных подпроцесса.

Проблема этого потенциального решения заключается в том, что оно сохраняет весь вывод перед его усечением.

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

Альтернатива OUT_DATA=$($COMMAND_TO_RUN | head -c 10000)отменяет команду, когда считываются первые 10 КБ вывода, и мне нужно, чтобы команда выполнилась до конца, чтобы зафиксировать ее состояние выхода.

Я могу сделать это довольно легко в python, но надеюсь на bashединственное решение. И также не прибегая к записи на диск.

решение1

С функцией. Для удобства чтения в примере ниже команда и т.п. жестко закодированы.

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

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

headпередает не более желаемого объема данных в stdout функции. Если данных больше, catотбрасывает их без прерывания du. Статус выхода duизвлекается из PIPESTATUSмассива и возвращается функцией.

Примечание: мои переменные используют lower case; см.этот ответ.


Без функции то же самое решение выглядит так:

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

По моему мнению, так текст становится менее читабельным.

решение2

Это ограничивает объем захвата, но я предполагаю, что он завершается со readстатусом выхода s (я не знаю, останавливается ли он, но останавливает команду, как headэто было бы, потому что статус выхода не соблюдается: `

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

Похоже, что команда выполняется до конца, но вы не получаете статус завершения команды, а получаете readстатус завершения s, что бесполезно.

Пример

$ 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

Я предполагаю, что тот факт, что файл затронут, означает, что команда не прерывается после захвата запрошенного количества символов.

Возможно, вы могли бы записать статус выхода в файл в подоболочке:

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

Связанный контент