Bash scripts avec tmux pour lancer une fenêtre à 4 volets
Quelqu'un Peut aider à expliquer ce qui se passe avec tmux, bash, et exec? J'essaie de configurer une session tmux avec une fenêtre à 4 volets. Idéalement, je veux exécuter une commande dans 3 des volets: par exemple un serveur Ruby Thin et quelques démons Ruby. C'est ce que j'ai jusqu'à présent:
~/.bin/tmux-foo:
#!/bin/sh
tmux new-session -d -s foo 'exec pfoo "bundle exec thin start"'
tmux rename-window 'Foo'
tmux select-window -t foo:0
tmux split-window -h 'exec pfoo "bundle exec compass watch"'
tmux split-window -v -t 0 'exec pfoo "rake ts:start"'
tmux split-window -v -t 1 'exec pfoo'
tmux -2 attach-session -t foo
~/.bin/pfoo:
#!/bin/bash
cd ~/projects/foo
rvm use ree
# here I want to execute command1 2 3 or 4...
exec $SHELL
Tout fonctionne... mais quand i ctlr-c dans le premier volet qui exécute le serveur thin, il arrête le serveur thin et retourne au shell. Toutefois, la commande est pas dans l'histoire; c'est-à-dire que si j'appuie sur la touche up, Je n'obtiens pas la commande bundle exec thin start... Je reçois une autre commande de mon histoire bash. Je me demande s'il y a un moyen d'organiser ces scripts pour que j'obtienne les commandes dans l'historique bash.
Aussi... J'ai essayé de nombreuses combinaisons de exec, exec $SHELL -s ..., et exec $SHELL -s ... -I et je ne suis pas tout à fait sûr de ce qui se passe...
Quelqu'un Peut aider à expliquer l'idée générale de ce qui se passe avec tmux et bash et exec ici?
3 réponses
Comme d'autres l'ont mentionné, vos commandes sont exécutées par le script shell avant que ne lance votre $SHELL; Il n'y a aucun moyen général que l'instance de $SHELL puisse savoir ce que son parent a couru avant de le démarrer.
Pour obtenir la "commande initiale" dans l'historique du shell, vous devez alimenter les frappes de commande directement à l'instance de $SHELL elle-même (après son démarrage, bien sûr). Dans d'autres contextes, je pourrais suggérer d'utiliser un petit programme Expect pour générer une instance de $SHELL, nourrir les frappes de touches, puis utilisez interact pour attacher l'ats à l' s'attendre-engendré $SHELL.
, Mais dans le contexte de tmux, il suffit d'utiliser send-keys:
#!/bin/sh
tmux new-session -d -s foo 'exec pfoo'
tmux send-keys 'bundle exec thin start' 'C-m'
tmux rename-window 'Foo'
tmux select-window -t foo:0
tmux split-window -h 'exec pfoo'
tmux send-keys 'bundle exec compass watch' 'C-m'
tmux split-window -v -t 0 'exec pfoo'
tmux send-keys 'rake ts:start' 'C-m'
tmux split-window -v -t 1 'exec pfoo'
tmux -2 attach-session -t foo
Tmuxinator vous permet de spécifier cela avec un joli fichier yaml. Pour votre cas, vous pourriez avoir:
# ~/.tmuxinator/foo.yml
# you can make as many tabs as you wish...
project_name: foo
project_root: ~/projects/foo
rvm: ree
tabs:
- main:
layout: tiled
panes:
- bundle exec thin start
- bundle exec compass watch
- #empty, will just run plain bash
- rake ts:start
Vous pouvez bien sûr avoir des fenêtres supplémentaires, etc.
Vous exécutez la commande, puis entrez le shell interactif; la commande exécutée à partir du script, n'étant pas dans un shell interactif, n'est pas enregistrée dans l'historique. Vous voulez vraiment un moyen de farcir (c'est un terme technique :) il était une fois TIOCSTI pour "terminal ioctl (): stuff input") Entrée pour le shell dans la fenêtre.
Avec tmux, il semble que vous utilisiez des tampons pour cela. Quelque chose dans le sens de (non testé)
#! /bin/bash
cd ~/projects/foo
rvm use ree
if [[ $# != 0 ]]; then
tmux set-buffer "$(printf '%s\n' "$*")" \; paste-buffer -d
fi
exec ${SHELL:-/bin/sh}