Вопрос: Запустите интерактивную подстроку bash с исходными командами без немедленного возврата в оболочку (супер)


Я хочу запустить bash subshell, (1) запустить несколько команд, (2), а затем остаться в этой подоболочке, чтобы сделать, как мне заблагорассудится. Я могу сделать каждый из них индивидуально:

  1. Выполнить команду, используя -c флаг:

    $> bash -c "ls; pwd; <other commands...>"
    

    однако после выполнения команд он сразу возвращается в «супер» оболочку. Я также могу запустить интерактивную подоболочку:

  2. Начать новую bash обработать:

    $> bash
    

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

    $> bash -c "ls; pwd; <other commands>; exec bash"
    

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

Я хочу сделать это на одной строке. Как только я выхожу из подоболочки, я должен вернуться в обычную «супер» оболочку без инцидентов. Должен быть способ ~~

NB: То, что я не прошу ...

  1. не спрашивая, где взять верхнюю страницу
  2. не спрашивая, как читать инициализацию команд из файла ... Я знаю, как это сделать, это не то решение, которое я ищу
  3. не интересуется использованием экрана tmux или gnu
  4. не заинтересованы в придании этому контексту. I.e, вопрос должен быть общим, а не для какой-либо конкретной цели
  5. если это возможно, я хочу избежать использования обходных решений, которые выполняют то, что я хочу, но «грязным» способом. Я просто хочу сделать это на одной строке. В частности, я не хочу делать что-то вроде xterm -e 'ls'

55
2018-03-09 15:12


Источник


Я могу представить решение Expect, но вряд ли это тот, который вам нужен. Каким образом exec bash решение неподходящее для вас? - glenn jackman
@glennjackman извините, я не знаком с жаргоном. Что такое «Ожидаемое решение»? Так же exec bash решение включает в себя две отдельные подоболочки. Я хочу одну непрерывную подоболочку. - SABBATINI Luca
Красота exec это оно заменяет первая подоболочка со второй, поэтому вы оставите 1 оболочку ниже родителя. Если ваши команды инициализации задают переменные среды, они будут существовать в оболочке exec'ed. - glenn jackman
возможно такой же stackoverflow.com/questions/7120426/... - Ciro Santilli 新疆改造中心 六四事件 法轮功
я сдался, но я не видел этого здесь, поэтому FWIW: RUN_CONDITIONAL=true bash --login и поместите свои команды в .bash_profile или w / e. не знаю о переносимости. - Cory Mawhorter


Ответы:


Это можно легко сделать с помощью временные именованные трубы:

bash --init-file <(echo "ls; pwd")

Кредит для этого ответа идет на комментарий от Ли Райан, Я нашел это действительно полезным, и это менее заметно в комментариях, поэтому я подумал, что это должен быть его собственный ответ.


51
2018-04-02 20:17



Это, по-видимому, означает, что $HOME/.bashrc не выполняется. Он должен быть включен из временного именованного канала. - Hubro
Чтобы уточнить, что-то вроде этого: bash --init-file <(echo ". \"$HOME/.bashrc\"; ls; pwd") - Hubro
Это так грубо, но оно действительно работает. Я не могу поверить, что bash не поддерживает это напрямую. - Pat Niemeyer
@Hubro, какова цель .  в команде? Без этого я получаю «разрешение отклонено» на моем .bashrc, но я не понимаю, почему и как . исправляет его. - Gus
@Gus, . является синонимом source команда: ss64.com/bash/source.html, - Jonathan Potter


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

echo "ls; pwd" > initfile
bash --init-file initfile

7
2018-03-09 16:21



Для хорошего эффекта вы можете заставить файл temp удалить себя, включив rm $BASH_SOURCE в этом. - Eduardo Ivanec
Эдуардо, спасибо. Это хорошее решение, но ... вы говорите, что это невозможно сделать без чтобы играть с файлами ввода / вывода. Есть очевидные причины, по которым я бы предпочел сохранить это как автономную команду, потому что в момент, когда файлы попадают в микс, мне придется начинать беспокоиться о том, как создавать случайные временные файлы, а затем, как вы упомянули, удалять их. Для этого требуется гораздо больше усилий, если я хочу быть строгим. Отсюда стремление к более минималистичному, изящному решению. - SABBATINI Luca
Используйте утилиту mktemp для создания уникального временного файла. - cjc
@SABBATINILuca: Я не говорю ничего подобного. Это всего лишь способ, и mktemp решает проблему временного файла, как указано в @cjc. удар мог поддержка чтения команд init из stdin, но насколько я могу сказать, это не так. Specyfing - в качестве файла инициализации и для их работы половина работает, но затем Bash выходит (возможно, потому, что обнаружил конвейер). Элегантное решение IMHO - использовать exec. - Eduardo Ivanec
Это старый вопрос, но Bash может создавать временные именованные каналы, используя следующий синтаксис: bash --init-file <(echo "ls; pwd"). - Lie Ryan


Попробуйте это вместо этого:

$> bash -c "ls;pwd;other commands;$SHELL"

$SHELL  Это делает оболочку открытой в интерактивном режиме, ожидая закрытия с exit,


3
2018-02-23 03:50



FYI, после этого открывается новая оболочка, поэтому, если какая-либо из команд влияет на состояние текущей оболочки (например, поиск файла), она может работать не так, как ожидалось - ThiefMaster


«Ожидаемое решение», на которое я имел в виду, это программирование оболочки bash с Ожидайте языка программирования:

#!/usr/bin/env expect
set init_commands [lindex $argv 0]
set bash_prompt {\$ $}              ;# adjust to suit your own prompt
spawn bash
expect -re $bash_prompt {send -- "$init_commands\r"}
interact
puts "exiting subshell"

Вы запустите это как: ./subshell.exp "ls; pwd"


1
2018-03-09 19:56



Думаю, это будет иметь преимущество в регистрации команд в истории, я ошибаюсь? Также мне интересно, если в этом случае выполняется bashrc / profile? - muhuk


Если sudo -E bash не работает, я использую следующее, которое оправдало мои ожидания:

sudo HOME=$HOME bash --rcfile $HOME/.bashrc

Я устанавливаю HOME = $ HOME, потому что хочу, чтобы мой новый сеанс имел HOME, установленный в ДОМЕ пользователя моего пользователя, а не в корневом ДОМЕ, который по умолчанию используется в некоторых системах.


1
2017-09-16 15:07





менее элегантный, чем --init-file, но, возможно, более измеримым:

fn(){
    echo 'hello from exported function'
}

while read -a commands
do
    eval ${commands[@]}
done

0
2018-04-17 01:37





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

$ ( ls; pwd; exec $BASH; )
bar     foo     howdy
/tmp/hello/
bash-4.4$ 
bash-4.4$ exit
$

Команды закрытия с круглыми скобками делают bash порождать подпроцесс для запуска этих команд, поэтому вы можете, например, изменить среду, не затрагивая родительскую оболочку. Это в основном более читаемо, эквивалентное bash -c "ls; pwd; exec $BASH",

Если это все еще выглядит многословным, есть два варианта. Один из них заключается в том, чтобы этот фрагмент был как функция:

$ run() { ( eval "$@"; exec $BASH; ) }
$ run 'ls; pwd;'
bar     foo     howdy
/tmp/hello/
bash-4.4$ exit
$ run 'ls;' 'pwd;'
bar     foo     howdy
/tmp/hello/
bash-4.4$ exit
$

Другой - сделать exec $BASH короче:

$ R() { exec $BASH; }
$ ( ls; pwd; R )
bar     foo     howdy
/tmp/hello/
bash-4.4$ exit
$

Мне лично нравится R больше, потому что нет необходимости играть с экранирующими строками.


0
2017-08-14 21:51