Je veux exécuter un sous-shell bash, (1) exécuter quelques commandes, (2) puis rester dans ce sous-shell pour faire ce que je veux. Je peux faire chacun de ces éléments individuellement:
Exécutez la commande à l'aide de -c
drapeau:
$> bash -c "ls; pwd; <other commands...>"
cependant, il revient immédiatement au "super" Shell après l'exécution des commandes. Je peux aussi simplement lancer un sous-shell interactif:
Démarrer un nouveau processus bash
:
$> bash
et il ne quittera pas le sous-shell jusqu'à ce que je le dise explicitement ... mais je ne peux exécuter aucune commande initiale. La solution la plus proche que j'ai trouvée est:
$> bash -c "ls; pwd; <other commands>; exec bash"
qui fonctionne, mais pas comme je le voulais, car il exécute les commandes données dans un sous-shell, puis en ouvre une autre pour l'interaction.
Je veux le faire sur une seule ligne. Une fois que j'ai quitté le sous-shell, je devrais retourner au Shell "super" normal sans incident. Il doit y avoir un moyen ~~
NB: Ce que je ne demande pas ...
xterm -e 'ls'
Cela peut être facilement fait avec canaux nommés temporaires :
bash --init-file <(echo "ls; pwd")
Le mérite de cette réponse revient au commentaire de Lie Ryan . J'ai trouvé cela vraiment utile, et c'est moins perceptible dans les commentaires, alors j'ai pensé que ce devrait être sa propre réponse.
Vous pouvez le faire de manière détournée avec un fichier temporaire, même si cela prendra deux lignes:
echo "ls; pwd" > initfile
bash --init-file initfile
Essayez plutôt ceci:
$> bash -c "ls;pwd;other commands;$Shell"
$Shell
Il ouvre le Shell en mode interactif, en attendant sa fermeture avec exit
.
La "solution attendue" à laquelle je faisais référence était la programmation d'un shell bash avec le langage de programmation Expect :
#!/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"
Vous exécuteriez cela comme: ./subshell.exp "ls; pwd"
Pourquoi ne pas utiliser des sous-coquilles natives?
$ ( ls; pwd; exec $BASH; )
bar foo howdy
/tmp/hello/
bash-4.4$
bash-4.4$ exit
$
Le fait de placer des commandes entre parenthèses fait de bash spawn un sous-processus pour exécuter ces commandes, vous pouvez donc, par exemple, modifier l'environnement sans affecter le shell parent. C'est essentiellement l'équivalent plus lisible que le bash -c "ls; pwd; exec $BASH"
.
Si cela semble encore verbeux, il y a deux options. L'une consiste à avoir cet extrait de code en fonction:
$ 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
$
Une autre consiste à faire exec $BASH
plus court:
$ R() { exec $BASH; }
$ ( ls; pwd; R )
bar foo howdy
/tmp/hello/
bash-4.4$ exit
$
Personnellement, j'aime davantage l'approche R
, car il n'est pas nécessaire de jouer avec des chaînes d'échappement.
Si Sudo -E bash
ne fonctionne pas, j'utilise ce qui suit, ce qui a répondu à mes attentes jusqu'à présent:
Sudo HOME=$HOME bash --rcfile $HOME/.bashrc
J'ai défini HOME = $ HOME parce que je veux que ma nouvelle session ait HOME défini sur HOME de mon utilisateur, plutôt que sur HOME de root, ce qui se produit par défaut sur certains systèmes.
moins élégant que --init-file
, mais peut-être plus instrumentable:
fn(){
echo 'hello from exported function'
}
while read -a commands
do
eval ${commands[@]}
done
J'accomplis essentiellement la même chose en utilisant simplement un script, généralement dans le but de définir des variables d'environnement à utiliser dans un répertoire de projet spécifique;
$ cat Shell.sh
#!/bin/bash
export PATH=$PWD/bin:$PATH
export USERNAME=foo
export PASSWORD=bar
export DB_SERVER=http://localhost:6001
bash
$ echo ${USERNAME:-none}
none
$ ./Shell.sh
$ echo $USERNAME
foo
Cela vous dépose dans un shell interactif bash
une fois tous les ajustements d'environnement effectués; vous pouvez mettre à jour ce script avec les autres commandes pertinentes que vous souhaitez exécuter.