Подтвердить что ты не робот

Как вызвать bash, запустить команды внутри новой оболочки, а затем вернуть управление пользователю?

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

Я пробовал:

$ bash -lic "some_command"

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

Еще одна деталь, которая может повлиять на ответы: если я смогу заставить это работать, я буду использовать ее в моем .bashrc как псевдоним (es), поэтому бонусные баллы для реализации alias!

4b9b3361

Ответ 2

Это поздний ответ, но у меня была одна и та же проблема, и google отправил меня на эту страницу, поэтому для полноты вот как я столкнулся с проблемой.

Насколько я могу судить, bash не имеет возможности делать то, что хотел сделать оригинальный плакат. Опция -c всегда будет возвращаться после выполнения команд.

Сломанное решение: простейшая и очевидная попытка:

bash -c 'XXXX ; bash'

Это частично работает (хотя и с дополнительным слоем подкласса). Однако проблема заключается в том, что, хотя суб-оболочка наследует экспортируемые переменные среды, псевдонимы и функции не наследуются. Таким образом, это может работать для чего-то, но не является общим решением.

Лучше: чтобы создать динамический файл запуска и вызвать bash с этим новым файлом инициализации, убедитесь, что ваш новый файл инициализации вызывает ваш обычный ~/.bashrc, если это необходимо.

# Create a temporary file
TMPFILE=$(mktemp)

# Add stuff to the temporary file
echo "source ~/.bashrc" > $TMPFILE
echo "<other commands>" >> $TMPFILE
echo "rm -f $TMPFILE" >> $TMPFILE

# Start the new bash shell 
bash --rcfile $TMPFILE

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

Примечание. Я не уверен, что /etc/bashrc обычно называют частью обычной оболочки без входа. Если это так, вы можете захотеть указать источник /etc/bashrc, а также ваш ~/.bashrc.

Ответ 3

Вы можете передать --rcfile в Bash, чтобы заставить его читать файл по вашему выбору. Этот файл будет считан вместо вашего .bashrc. (Если это проблема, источник ~/.bashrc от другого script.)

Изменить:. Таким образом, функция запуска новой оболочки с материалом из ~/.more.sh будет выглядеть примерно так:

more() { bash --rcfile ~/.more.sh ; }

... и в .more.sh у вас будут команды, которые вы хотите выполнить при запуске оболочки. (Я полагаю, было бы элегантно избегать отдельного файла запуска - вы не можете использовать стандартный ввод, потому что тогда оболочка не будет интерактивной, но вы можете создать загрузочный файл из этого документа во временном месте, а затем прочитать его.)

Ответ 4

Вы можете получить нужную функциональность, используя script вместо ее запуска. например:

$cat script
cmd1
cmd2
$ . script
$ at this point cmd1 and cmd2 have been run inside this shell

Ответ 5

В соответствии с ответом daveraja, здесь есть сценарий bash, который решит цель.

Рассмотрим ситуацию, если вы используете C-shell и хотите выполнить команду, не выходя из контекста/окна C-shell, следующим образом:

Команда для выполнения: Поиск точного слова "Тестирование" в текущем каталоге рекурсивно только в файлах *.h, *.c

grep -nrs --color -w --include="*.{h,c}" Testing ./

Решение 1. Войдите в bash из C-shell и выполните команду

bash
grep -nrs --color -w --include="*.{h,c}" Testing ./
exit

Решение 2. Запишите нужную команду в текстовый файл и выполните ее, используя bash.

echo 'grep -nrs --color -w --include="*.{h,c}" Testing ./' > tmp_file.txt
bash tmp_file.txt

Решение 3: Запустите команду в той же строке, используя bash

bash -c 'grep -nrs --color -w --include="*.{h,c}" Testing ./'

Решение 4. Создайте sciprt (единовременно) и используйте его для всех будущих команд

alias ebash './execute_command_on_bash.sh'
ebash grep -nrs --color -w --include="*.{h,c}" Testing ./

Сценарий заключается в следующем,

#!/bin/bash
# =========================================================================
# References:
# https://stackoverflow.com/a/13343457/5409274
# https://stackoverflow.com/a/26733366/5409274
# https://stackoverflow.com/a/2853811/5409274
# https://stackoverflow.com/a/2853811/5409274
# https://www.linuxquestions.org/questions/other-%2Anix-55/how-can-i-run-a-command-on-another-shell-without-changing-the-current-shell-794580/
# https://www.tldp.org/LDP/abs/html/internalvariables.html
# https://stackoverflow.com/a/4277753/5409274
# =========================================================================

# Enable following line to see the script commands
# getting printing along with their execution. This will help for debugging.
#set -o verbose

E_BADARGS=85

if [ ! -n "$1" ]
then
  echo "Usage: 'basename $0' grep -nrs --color -w --include=\"*.{h,c}\" Testing ."
  echo "Usage: 'basename $0' find . -name \"*.txt\""
  exit $E_BADARGS
fi  

# Create a temporary file
TMPFILE=$(mktemp)

# Add stuff to the temporary file
#echo "echo Hello World...." >> $TMPFILE

#initialize the variable that will contain the whole argument string
argList=""
#iterate on each argument
for arg in "[email protected]"
do
  #if an argument contains a white space, enclose it in double quotes and append to the list
  #otherwise simply append the argument to the list
  if echo $arg | grep -q " "; then
   argList="$argList \"$arg\""
  else
   argList="$argList $arg"
  fi
done

#remove a possible trailing space at the beginning of the list
argList=$(echo $argList | sed 's/^ *//')

# Echoing the command to be executed to tmp file
echo "$argList" >> $TMPFILE

# Note: This should be your last command
# Important last command which deletes the tmp file
last_command="rm -f $TMPFILE"
echo "$last_command" >> $TMPFILE

#echo "---------------------------------------------"
#echo "TMPFILE is $TMPFILE as follows"
#cat $TMPFILE
#echo "---------------------------------------------"

check_for_last_line=$(tail -n 1 $TMPFILE | grep -o "$last_command")
#echo $check_for_last_line

#if tail -n 1 $TMPFILE | grep -o "$last_command"
if [ "$check_for_last_line" == "$last_command" ]
then
  #echo "Okay..."
  bash $TMPFILE
  exit 0
else
  echo "Something is wrong"
  echo "Last command in your tmp file should be removing itself"
  echo "Aborting the process"
  exit 1
fi

Ответ 6

Добавьте к ~/.bashrc раздел, подобный этому:

if [ "$subshell" = 'true' ]
then
    # commands to execute only on a subshell
    date
fi
alias sub='subshell=true bash'

Затем вы можете запустить подоболочку с помощью sub.

Ответ 7

Принятый ответ действительно полезен! Просто добавить, что подстановка процесса (т. <(COMMAND)) не поддерживается в некоторых оболочках (например, dash).

В моем случае я пытался создать пользовательское действие (в основном, однострочный сценарий оболочки) в файловом менеджере Thunar, чтобы запустить оболочку и активировать выбранную виртуальную среду Python. Моя первая попытка была:

urxvt -e bash --rcfile <(echo ". $HOME/.bashrc; . %f/bin/activate;")

где %f - это путь к виртуальной среде, обрабатываемой Thunar. Я получил ошибку (запустив Thunar из командной строки):

/bin/sh: 1: Syntax error: "(" unexpected

Тогда я понял, что мой sh (по существу, dash) не поддерживает процесс подстановки.

Мое решение состояло в том, чтобы вызвать bash на верхнем уровне для интерпретации подстановки процесса за счет дополнительного уровня оболочки:

bash -c 'urxvt -e bash --rcfile <(echo "source $HOME/.bashrc; source %f/bin/activate;")'

В качестве альтернативы я попытался использовать здесь документ для dash но безуспешно. Что-то вроде:

echo -e " <<EOF\n. $HOME/.bashrc; . %f/bin/activate;\nEOF\n" | xargs -0 urxvt -e bash --rcfile

PS: У меня недостаточно репутации, чтобы оставлять комментарии, модераторы, пожалуйста, не стесняйтесь перемещать их в комментарии или удалять, если они не помогли с этим вопросом.