Как выполнить вывод команды в текущей оболочке?
Мне хорошо известно утилита 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
.
Ответ 7
Я думаю, что ваше решение - подстановка команды с обратными шагами: http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_04.html
См. раздел 3.4.5
Ответ 8
Почему бы не использовать source
затем?
$ ls | sed ... > out.sh ; source out.sh
Ответ 9
Чтобы использовать решение mark4o на bash 3.2 (macos), здесь вместо конвейеров, как в этом примере, можно использовать следующую строку:
. /dev/stdin <<< "$(grep '^alias' ~/.profile)"