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}