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?

50
demandé sur Aaron Gibralter 2011-03-27 08:42:30

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
49
répondu Chris Johnsen 2011-10-11 02:43:49

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.

12
répondu Hamish Downer 2012-04-18 20:01:19

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}
3
répondu geekosaur 2011-03-27 05:26:09