Как динамически использовать перенаправление вывода?

Предположим, что у Вас есть переменные server и dir определенный, можно сделать

$ dir="~"
$ server="user@server.com"
$ scp $server:$dir/$(ssh $server 'ls -t $dir | head -1') .

Где Вы сначала ищете новейший файл и затем копируете его.

Примечание: Я не проверял его на надежность (например, при этом последняя запись была папкой),

5
09.06.2015, 01:50
5 ответов

Для этой цели я обычно определяю функцию типа run. В большинстве случаев она может корректно обрабатывать споры с пробелами и прочими.

#!/bin/bash

run() {
        if $DEBUG; then
                v=$(exec 2>&1 && set -x && set -- "$@")
                echo "#${v#*--}"
                "$@"
        else
                "$@" >/dev/null 2>&1
        fi
}

DEBUG=false
run echo "bla"

DEBUG=true
run echo "bla"
run printf "%s . %s . %s\n" bla "more bla" bla

Вывод:

$ bash debug.sh 
# echo bla
bla
# printf '%s . %s . %s\n' bla 'more bla' bla
bla . more bla . bla
4
27.01.2020, 20:32

В вашем случае эхо обрабатывают $ Redir как строковый аргумент. Тем не менее, вы хотите что-то вроде:

~$ echo "bla" >/dev/null 2>&1
~$ REDIR='>/dev/null 2>&1'
~$ eval "echo bla $REDIR"
~$

, если вы не пытаетесь сделать быстрое и грязное взломать, Weouter Verhelst имеет лучшее решение (и это действительно не так долго или сложно).

2
27.01.2020, 20:32

Перенаправление не является командой, поэтому вы не можете выполнить ее таким образом. Вы можете сделать это, если вы используете EVAL , но это открывает банку червей.

Лучший способ сделать то, что вы пытаетесь сделать, это иметь функцию для отладки вывода:

function debugprint {
    if [ ! -z "$debug" ]; then
        echo "$1"
    fi
}

debugprint "$(echo 'bla' 2>&1)"

Это будет перенаправить стандартную ошибку на стандартный выход, а затем вызов DebugPrint с выходом в виде аргумент Теперь все, что вам нужно сделать, это установить $ Debug к чему-то непустому, когда вы хотите отладить.

Конечно, это также открытие (разные) банки червей (связанных с цитированием). Возможно, вы захотите просто использовать SET -X вместо этого, который может или не может сделать достаточно для ваших потребностей отладки.

6
27.01.2020, 20:32

возможно, вы могли бы использовать функцию для конвейерного вывода вывода и позволить ему выполнять перенаправление:

#! /bin/bash

DEBUGMODE="Debug"

function handleStdOut {
    if [[ "$DEBUGMODE" == "Debug" ]]
    then
        echo "Debugging..."
        cat
        echo "Done"
    else
         cat > /dev/null
    fi 
}

echo "bla" | handleStdOut
2
27.01.2020, 20:32

Для каждой функции оболочки, которую я пишу, я делаю то же самое.

fn(){ 
    echo some normal stderr debug stuff             >&2     #if $DBG 2>stderr
    dd if="\$DBG/please/report/on/this/file"                #ditto
    echo I DEFINITELY need to handle this           >&3     #always stderr
    ( PATH=; ".some" oops I expect to handle )     2>&4     #always /dev/null
    echo and the regular stuff                              #always unaffected
}   4<>/dev/null 3>&2 2>&"$((${#DBG}?3:4))"

Мне это нравится по нескольким причинам.

  1. Использование оценки $ {# DBG} для len всегда гарантирует целочисленное значение > = 0 для теста - независимо от того, что $ DBG может на самом деле содержать. Это делает математические вычисления безопасными, например, если DBG = IFS = 0 .

  2. Каждый раз, когда функция запускается, она должна выполнять только фактическую open () на / dev / null один раз - в любой другой раз я перенаправляю на / dev / null Я делаю это с установленным дескриптором в #fd> & 4 .

  3. Вывод отладки - как я мог бы включить с помощью set -x - для функций в моих интерактивных оболочках сбрасывается по умолчанию , если я явно не установил переменную среды $ DBG на любое ненулевое значение.

    • Когда $ DBG не является нулевым, математическое расширение для перенаправления будет указывать на себя - оно оценивается как 2> & 3 .
    • Но в противном случае он оценивается как 2> & 4 и переходит к открытому дескриптору / dev / null .
    • Обычно мне не нужно видеть 20 строк трассировки выполнения функции, которую я уже одобрил и сохранил в ~ / .sh / fn / ... , но команда -строка, в которой он участвует, - это, вероятно, совсем другое дело, если я установил -x .
    • Это также удобно, когда $ DBG имеет значение null / не установлено, но set -x включен , поскольку он открывает выход eval для каждой команды в $ PS4 , который не попадает в stderr, но #fd> & 3 все еще может попасть туда.
  4. Это разрешает наследование разумным способом.

    • Функция, вызывающая других, не может каким-либо образом повлиять на значение $ DBG , что может позволить им начать запись в stderr по умолчанию, если это уже невозможно.
    • Если $ DBG не установлен или обнулен, все дочерние функции, которые он вызывает, теряют даже значение # fd3 , если только он не вызывает их с помощью child_fn 2> & 3 - в этом случае они получат ту же возможность, что и их родитель, для явной записи в stderr.
    • Он может также отключить $ DBG , чтобы отключить эти дочерние функции, даже если $ DBG уже установлен.
    • И он может установить $ DBG , чтобы функции верхнего уровня, вызываемые после , включали вывод stderr по умолчанию.
  5. Я сохраняю копию stderr на #fd> & 3 , и поэтому, если функция должна, она все равно может писать в stderr явно на этот дескриптор (кроме случаев, указанных выше) .

  6. Дескрипторы закрываются и не влияют на текущие значения оболочки для fds 2, 3, 4, потому что они связаны только с составной командой, которая является оболочкой для функции.

    • Очистка с помощью {3,4}> & - никогда не требуется.
2
27.01.2020, 20:32

Теги

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