Как закрыть дескриптор именованного файла, не закрывая стандартный ввод/стандартный вывод?

Все команды в конвейере запускаются практически одновременно. Их синхронизирует только ввод-вывод по каналу. Кроме того, канал может содержать столько информации, сколько позволяет буфер канала.

Таким образом, вы не можете избежать запуска одного этапа конвейера, потому что

  1. команда на этом этапе запускается, как только запускаются все остальные этапы, и
  2. Если бы команда не использовала входные данные, поступающие по конвейеру, она заблокировала бы предыдущие этапы конвейера.

Вместо этого запишите вывод в файл, дав конвейеру завершить работу. Затем используйте этот файл.

Пример (как функция с одним аргументом):

myman () {
    tmpfile=$( mktemp )

    if man -k "$1" | dmenu -l 20 | awk '{print $1}' | xargs -r man -Tpdf >"$tmpfile" && [ -s  "$tmpfile" ]
    then
        zathura "$tmpfile"
    fi

    rm -f "$tmpfile"
}

Кроме того, программа zathuraне будет запускаться, если конвейер выйдет из строя, (часть xargsвернет не -ноль )или сгенерированный файл будет пустым.

В оболочке bashвы также можете установить параметр оболочки pipefailс set -o pipefail, чтобы конвейер возвращал статус выхода первой неудачной команды в конвейере. И вы хотели бы сделать переменную tmpfilelocal:

myman () {
    local tmpfile=$( mktemp )

    if [ -o pipefail ]; then
        set -o pipefail
        trap 'set +o pipefail' RETURN
    fi

    if man -k "$1" | dmenu -l 20 | awk '{print $1}' | xargs -r man -Tpdf >"$tmpfile"
    then
        zathura "$tmpfile"
    fi

    rm -f "$tmpfile"
}

Это устанавливает параметр pipefailна время действия функции, если он еще не был установлен, а затем при необходимости снимает его. Он избавляется от теста -sв выходном файле.

4
17.04.2021, 01:21
0 ответов

Теги

Похожие вопросы