Deve ser muito simples ou muito complexo, mas não consegui encontrar nada sobre isso ... Estou tentando abrir uma nova instância do bash, executar alguns comandos dentro dela e devolver o controle ao usuário dentro dela mesma instância .
Eu tentei:
$ bash -lic "some_command"
mas isso é executado some_command
dentro da nova instância e, em seguida, fecha-a. Eu quero que fique aberto.
Mais um detalhe que pode afetar as respostas: se eu conseguir fazer isso funcionar, vou usá-lo no .bashrc
(s) meu (s) apelido (s), portanto, pontos de bônus para uma alias
implementação!
alias shortcut='bash -lic "some_command"'
no meu .bashrc e executarshortcut
e ter um novo shellsome_command
já executado nele.Respostas:
bash --rcfile <(echo '. ~/.bashrc; some_command')
dispensa a criação de arquivos temporários. Pergunta em outros sites:
fonte
The system cannot find the file specified.
cat ~/.bashrc
? 2) Funcionacat <(echo a)
? 3) Funcionabash --rcfile somefile
?bash.exe --rcfile ^<^(echo 'source $HOME/.bashrc; ls; pwd'^)
deve ser executado no prompt de comando do Windows.sudo bash --init-file <(echo "ls; pwd")
ousudo -iu username bash --init-file <(echo "ls; pwd")
?Esta é uma resposta tardia, mas eu tive exatamente o mesmo problema e o Google me enviou para esta página, portanto, para completar, aqui está como eu resolvi o problema.
Pelo que eu posso dizer,
bash
não tem a opção de fazer o que o autor do cartaz original queria fazer. A-c
opção sempre retornará após a execução dos comandos.Solução quebrada : a tentativa mais simples e óbvia de contornar isso é:
bash -c 'XXXX ; bash'
Isso funciona parcialmente (embora com uma camada extra de sub-casca). No entanto, o problema é que, embora um sub-shell herde as variáveis de ambiente exportadas, aliases e funções não são herdados. Portanto, isso pode funcionar para algumas coisas, mas não é uma solução geral.
Melhor : a maneira de contornar isso é criar dinamicamente um arquivo de inicialização e chamar o bash com esse novo arquivo de inicialização, certificando-se de que seu novo arquivo init chame o regular,
~/.bashrc
se necessário.# 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
O bom é que o arquivo init temporário irá deletar a si mesmo assim que for usado, reduzindo o risco de não ser limpo corretamente.
Observação: não tenho certeza se / etc / bashrc geralmente é chamado como parte de um shell normal sem login. Nesse caso, você pode querer fonte de / etc / bashrc assim como seu
~/.bashrc
.fonte
rm -f $TMPFILE
coisa faz isso. Na verdade, não me lembro do caso de uso que tive para isso e agora uso técnicas de automação mais avançadas, mas este é o caminho a seguir!bash --rcfile <(echo ". ~/.bashrc; a=b")
trap
.Você pode passar
--rcfile
para o Bash para que ele leia um arquivo de sua escolha. Este arquivo será lido em vez do seu.bashrc
. (Se isso for um problema, fonte~/.bashrc
do outro script.)Edit: Portanto, uma função para iniciar um novo shell com o material de
~/.more.sh
seria semelhante a:more() { bash --rcfile ~/.more.sh ; }
... e
.more.sh
você teria os comandos que deseja executar quando o shell iniciar. (Suponho que seria elegante evitar um arquivo de inicialização separado - você não pode usar a entrada padrão porque o shell não será interativo, mas você pode criar um arquivo de inicialização a partir de um documento aqui em um local temporário e depois lê-lo.)fonte
Você pode obter a funcionalidade desejada fornecendo o script em vez de executá-lo. por exemplo:
fonte
alias=''
?Anexar a
~/.bashrc
uma seção como esta:if [ "$subshell" = 'true' ] then # commands to execute only on a subshell date fi alias sub='subshell=true bash'
Então você pode iniciar o subshell com
sub
.fonte
env subshell=true bash
(já que não vazará$subshell
para os comandos subsequentes): Usando env vs. usando export .env
. Para verificar se está definido ou não, eu usoecho $subshell
(em vezenv | grep subshell
daquele que você usa).A resposta aceita é muito útil! Apenas para adicionar que a substituição de processo (ou seja,
<(COMMAND)
) não é suportada em alguns shells (por exemplo,dash
).No meu caso, estava tentando criar uma ação personalizada (basicamente um script de shell de uma linha) no gerenciador de arquivos Thunar para iniciar um shell e ativar o ambiente virtual Python selecionado. Minha primeira tentativa foi:
urxvt -e bash --rcfile <(echo ". $HOME/.bashrc; . %f/bin/activate;")
onde
%f
está o caminho para o ambiente virtual manipulado por Thunar. Recebi um erro (executando Thunar na linha de comando):/bin/sh: 1: Syntax error: "(" unexpected
Então percebi que meu
sh
(essencialmentedash
) não suporta a substituição de processos.Minha solução foi invocar
bash
no nível superior para interpretar a substituição do processo, à custa de um nível extra de shell:bash -c 'urxvt -e bash --rcfile <(echo "source $HOME/.bashrc; source %f/bin/activate;")'
Como alternativa, tentei usar here-document,
dash
mas sem sucesso. Algo como:echo -e " <<EOF\n. $HOME/.bashrc; . %f/bin/activate;\nEOF\n" | xargs -0 urxvt -e bash --rcfile
PS: Não tenho reputação suficiente para postar comentários, moderadores, fiquem à vontade para mover para comentários ou removê-los se não ajudar com esta questão.
fonte
De acordo com a resposta de daveraja , aqui está um script bash que resolverá o propósito.
Considere uma situação se você estiver usando o C-shell e quiser executar um comando sem sair do contexto / janela do C-shell da seguinte forma,
Comando a ser executado : Pesquise a palavra exata 'Teste' no diretório atual recursivamente apenas em arquivos * .h, * .c
grep -nrs --color -w --include="*.{h,c}" Testing ./
Solução 1 : entre no bash do C-shell e execute o comando
bash grep -nrs --color -w --include="*.{h,c}" Testing ./ exit
Solução 2 : escreva o comando pretendido em um arquivo de texto e execute-o usando o bash
echo 'grep -nrs --color -w --include="*.{h,c}" Testing ./' > tmp_file.txt bash tmp_file.txt
Solução 3 : execute o comando na mesma linha usando o bash
bash -c 'grep -nrs --color -w --include="*.{h,c}" Testing ./'
Solução 4 : crie um sciprt (uma única vez) e use-o para todos os comandos futuros
alias ebash './execute_command_on_bash.sh' ebash grep -nrs --color -w --include="*.{h,c}" Testing ./
O script é o seguinte,
#!/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 "$@" 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
fonte
Aqui está outra variante (funcional):
Isso abre um novo terminal gnome e, no novo terminal, executa o bash. O arquivo rc do usuário é lido primeiro e, em seguida, um comando
ls -la
é enviado para execução ao novo shell antes de se tornar interativo. O último eco adiciona uma nova linha extra que é necessária para terminar a execução.gnome-terminal -- bash -c 'bash --rcfile <( cat ~/.bashrc; echo ls -la ; echo)'
Também acho útil às vezes decorar o terminal, por exemplo, com cores para melhor orientação.
gnome-terminal --profile green -- bash -c 'bash --rcfile <( cat ~/.bashrc; echo ls -la ; echo)'
fonte
Executar comandos em um shell de fundo
Basta adicionar
&
ao final do comando, por exemplo:fonte
$ bash --init-file <(echo 'some_command') $ bash --rcfile <(echo 'some_command')
Caso você não possa ou não queira usar a substituição de processo:
Outra maneira:
$ bash -c 'some_command; exec bash' $ sh -c 'some_command; exec sh'
sh
-somente forma (dash
,busybox
):fonte
ENV=script
parte) fosse removida ou reformulada para evitar ser confundida com um copiador gritante da resposta superior.ENV
+,sh
estão presentes nas outras respostas, mas principalmente enterradas em toneladas de texto ou cercadas por código desnecessário / não essencial. Acredito que ter um resumo breve e claro seria benéfico para todos.