Как выполнить вывод команды в текущей оболочке?

Мне хорошо известно утилита source (aka .), которая выведет содержимое из файла и выполнит его в текущей оболочке.

Теперь я преобразую текст в команды оболочки, а затем запускаю их следующим образом:

$ ls | sed ... | sh

ls - это просто случайный пример, исходный текст может быть любым. sed тоже, просто пример преобразования текста. Интересный бит - sh. Я передаю все, что попал в sh, и он запускает его.

Моя проблема заключается в том, что это означает запуск новой суб-оболочки. Я бы предпочел, чтобы команды выполнялись в моей текущей оболочке. Как я мог бы сделать с source some-file, если бы у меня были команды в текстовом файле.

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

В качестве альтернативы, я хотел бы запустить свою подклассу с теми же характеристиками, что и моя текущая оболочка.

Обновление

Хорошо, решения, использующие backtick, безусловно, работают, но мне часто нужно это делать, пока я проверяю и изменяю вывод, поэтому я бы предпочел, чтобы в конце концов был способ передать результат.

печатное обновление

А, вещь /dev/stdin выглядела настолько красивой, но в более сложном случае она не работала.

Итак, у меня есть это:

find . -type f -iname '*.doc' | ack -v '\.doc$' | perl -pe 's/^((.*)\.doc)$/git mv -f $1 $2.doc/i' | source /dev/stdin

Что гарантирует, что все файлы .doc имеют расширение в нижней части.

И что, кстати, можно обрабатывать с помощью xargs, но кроме точки.

find . -type f -iname '*.doc' | ack -v '\.doc$' | perl -pe 's/^((.*)\.doc)$/$1 $2.doc/i' | xargs -L1 git mv

Итак, когда я запускаю первый, он сразу выйдет, ничего не происходит.

Ответ 1

$ ls | sed ... | source /dev/stdin

UPDATE: Это работает в bash 4.0, а также tcsh и тире (если вы меняете source на .). По-видимому, это было ошибкой в ​​bash 3.2. Из bash 4.0 примечания к выпуску:

Исправлена ​​ошибка, вызвавшая `. ' чтобы не читать и выполнять команды из нерегулярных файлов, таких как устройства или именованные каналы.

Ответ 2

Для этой цели существует команда eval.

eval "$( ls | sed... )"

Больше из bash руководство:

Eval

          eval [arguments]

Аргументы объединены вместе в одну команду, которая затем считывается и выполняется, а его статус выхода возвращается как выход статус eval. Если нет аргументов или только пустых аргументов, статус возврата равен нулю.

Ответ 3

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

В любом случае - мне не нравится ответ source /dev/stdin, но я думаю, что нашел лучший. Это обманчиво просто:

echo ls -la | xargs xargs

Ницца, не так ли? На самом деле, это все равно не делает то, что вы хотите, потому что если у вас несколько строк, он будет конкатрировать их в одну команду, а не выполнять каждую команду отдельно. Итак, решение, которое я нашел, это:

ls | ... | xargs -L 1 xargs

параметр -L 1 означает, что вы используете (не более) 1 строку для выполнения каждой команды. Примечание:, если ваша строка заканчивается конечным пространством, она будет конкатенирована со следующей строкой! Поэтому убедитесь, что каждая строка заканчивается пробелом.

Наконец, вы можете сделать

ls | ... | xargs -L 1 xargs -t

чтобы увидеть, какие команды выполняются (-t является подробным).

Надеюсь, что кто-то прочитает это!

Ответ 4

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

source <(echo id)

Ответ 5

Я считаю, что это "правильный ответ" на вопрос:

ls | sed ... | while read line; do $line; done

То есть, можно подключиться к циклу while; команда команды read берет одну строку из ее stdin и присваивает ее переменной $line. $line затем становится командой, выполняемой в цикле; и он продолжается до тех пор, пока на его входе не будет никаких других строк.

Это все равно не будет работать с некоторыми структурами управления (например, с другим циклом), но в этом случае подходит для счета.

Ответ 6

`ls | sed ...`

Мне кажется, что ls | sed ... | source - будет красивее, но, к сожалению, source не понимает - как stdin.

Ответ 8

Почему бы не использовать source затем?

$ ls | sed ... > out.sh ; source out.sh

Ответ 9

Чтобы использовать решение mark4o на bash 3.2 (macos), здесь вместо конвейеров, как в этом примере, можно использовать следующую строку:

. /dev/stdin <<< "$(grep '^alias' ~/.profile)"