Bash: перенаправьте стандартный вход динамично в сценарии

Я пытался сделать это, чтобы решить, перенаправить ли stdin в файл или нет:

[ ...some condition here... ] && input=$fileName || input="&0"
./myScript < $input

Но это не работает, потому что, когда переменный $input является "&0", удар интерпретирует его как имя файла.

Однако я мог просто сделать:

if [ ...condition... ];then
    ./myScript <$fileName
else
    ./myScript

Проблема состоит в том, что./myScript является на самом деле долгой командной строкой, которую я не хочу копировать, и при этом я не хочу создавать функцию для него, потому что дело не в этом долго любой (это не стоит того).

Тогда мне пришло в голову делать это:

[ ...condition... ] && input=$fileName || input=  #empty
cat $input | ./myScript

Но это требует для выполнения еще одной команды и канала (т.е. подоболочка).
Есть ли иначе, это более просто и более эффективно?

29
задан GetFree 1 January 2010 в 01:33
поделиться

6 ответов

В первую очередь stdin - это файловый дескриптор 0 (ноль), а не 1 (то есть stdout).

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

[[ some_condition ]] && exec 3<"$filename" || exec 3<&0

some_long_command_line <&3

Обратите внимание, что показанная команда выполнит второе exec, если либо условие ложно , либо , если первое exec не срабатывает. Если вы не хотите, чтобы это не сработало, то вы должны использовать if / else:

if [[ some_condition ]]
then
    exec 3<"$filename"
else
    exec 3<&0
fi

, но последующие перенаправления из файлового дескриптора 3 будут неудачными, если первое перенаправление не сработало (после того, как условие было истинным).

.
24
ответ дан 28 November 2019 в 01:46
поделиться

Стандартный вход также может быть представлен файлом специального устройства /dev/stdin, так что использование в качестве имени файла будет работать.

file="/dev/stdin"
./myscript < "$file"
7
ответ дан 28 November 2019 в 01:46
поделиться
(
    if [ ...some condition here... ]; then
        exec <$fileName
    fi
    exec ./myscript
)

В подобложке, условно перенаправить stdin и выполнить скрипт.

7
ответ дан 28 November 2019 в 01:46
поделиться

Как насчет

function runfrom {
    local input="$1"
    shift
    case "$input" in
        -) "$@" ;;
        *) "$@" < "$input" ;;
    esac
}

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

Теперь вы пишите

[ ... condition ... ] && input="$fileName" || input="-"
runfrom "$input" my-complicated-command with many arguments

Я нахожу эти функции/команды, которые принимают команды в качестве аргументов (например, xargs(1)) очень полезными, и они хорошо сочиняются.

2
ответ дан 28 November 2019 в 01:46
поделиться

Это действительно очень неясное объяснение, и алгоритм, похоже, не исходит ни из одной из перечисленных ссылок.

Идея, кажется, чтобы сначала сделать случайный путь, выбирая начальный узел наугад и происхождение этого, выбирая случайных соседей столько, сколько это возможно. Когда больше соседей не может быть выбрано, или путь гамильтонов, или это не. Если это не, у этого последнего узла на пути есть некоторый сосед уже на пути (см. ниже), таким образом, поворотное средство делает край от последнего узла к соседу, уже находящемуся на пути, и удаляет одну из линий связи из соседа, которые были выбраны для пути. Затем происходит новый конец пути, с которого процесс продолжается.

Этот алгоритм предполагает, например, что отсутствуют узлы только с одним краем. Эти легко прикрыть, хотя: если есть один из них, просто начните с того, если их два, начните с одного из них и попытайтесь в итоге оказаться на другом, а если их больше двух, гамильтонова тропа быть не может.

-121--3665417-

c++ 0x будет иметь decltype , который можно использовать так:

int someInt;
decltype(someInt) otherIntegerVariable = 5;

, но для простых старых c++, к сожалению, нет.

Я полагаю, что decltype не очень поможет, хотя, поскольку вы хотите полиморфный тип, не объявленный тип. Самый прямой способ сделать то, что вы хотите, это попытаться динамически привести к определенному типу и проверить NULL .

struct A {
    virtual ~A() {}
};
struct B : public A {};
struct C : public A {};

int main() {
    A* x = new C;
    if(B* b_ptr = dynamic_cast<B*>(x)) {
        // it's a B
    } else if(C* c_ptr = dynamic_cast<C*>(x)) {
        // it's a C
    }
}
-121--4780477-

Если вы осторожны, вы можете использовать « eval » и свою первую идею.

[ ...some condition here... ] && input=$fileName || input="&1"
eval ./myScript < $input

Однако вы говорите, что «myScript» на самом деле является сложным вызовом команды; если он содержит аргументы, которые могут содержать места, необходимо быть очень осторожными, прежде чем принимать решение об использовании « eval ».

Честно говоря, беспокойство по поводу стоимости команды ' cat ', вероятно, не стоит неприятностей; вряд ли это будет узким местом.

Еще лучше разработать myScript так, чтобы он работал как обычный Unix-фильтр - он считывает со стандартного ввода, если ему не дается один или несколько файлов для работы (например, cat или grep в качестве примеров). Эта конструкция основана на долгом и здравом опыте - и поэтому стоит подражать, чтобы избежать необходимости иметь дело с такими проблемами, как эта.

2
ответ дан 28 November 2019 в 01:46
поделиться

Документы требуются 4 различных механизма хранения. Двигатель TapbackStorage пишет на сеанс.

-121--4648652-

Использование EVAL :

#! /bin/bash

[ $# -gt 0 ] && input="'"$1"'" || input="&1"

eval "./myScript <$input"

Эта простая подставка для MyScript

#! /usr/bin/perl -lp
$_ = reverse

производит следующий вывод:

$ ./myDemux myScript
pl- lrep/nib/rsu/ !#
esrever = _$

$ ./myDemux
foo
oof
bar
rab
baz
zab

Обратите внимание, что он обрабатывает пробелы в входах Слишком:

$ ./myDemux foo\ bar
eman eht ni ecaps a htiw elif

для ввода трубы до MyScript , используйте , используйте подстановку процесса :

$ ./myDemux <(md5sum /etc/issue)
eussi/cte/  01672098e5a1807213d5ba16e00a7ad0

Обратите внимание, что если вы попытаетесь трусить вывод напрямую, как в

$ md5sum /etc/issue | ./myDemux

Ожидание на входе от терминала, тогда как Ответ эфемиента не имеет этого недостатка.

Небольшое изменение производит желаемое поведение:

#! /bin/bash

[ $# -gt 0 ] && input="'"$1"'" || input=/dev/stdin
eval "./myScript <$input"
1
ответ дан 28 November 2019 в 01:46
поделиться