Published on

Running a Screen Session with Multiple Tabs and Long Running Tasks


Example dApp Monorepo Structure

In my post about monorepos, I spoke about how one advantage of a monorepo is that you can have scripts in the root of the project to help streamline your development process.

To illustrate how this works pretend I have an Ethereum decentralized app (dApp) monorepo that has the following structure:

            -> package.json
            -> App.js
            -> ...
            -> contracts
                            -> SomeContract1.sol
                            -> SomeContract2.sol
                            -> ...
            -> tests
                            -> SomeContract1-test.js
                            -> SomeContract2-test.js
                            -> ...
ui          -> package.json
            -> App.js
            -> ...

Makefile to Streamline the Process

An example of such a makefile that can help streamline my dev process by starting up all the pieces would look like below:

  screen -AdmS my-session-name -t tab0 bash
  screen -S my-session-name -X screen -t server -m yarn --cwd ./server run restart
  screen -S my-session-name -X screen -t ganache -m ganache-cli -p 8545
  screen -S my-session-name -X screen -t scripts-1 -m sleep 1000; yarn --cwd ./chain run clean-migrate; yarn --cwd ./server run bulkinsert
  screen -S my-session-name -X screen -t ui -m yarn --cwd ./ui run start

In the above:

  • screen -AdmS my-session-name -t tab0 bash:
    • this creates a new screen session (-S) called my-session-name.
    • adds a tab (-t) called tab0 to this session and runs bash in it.
    • detaches from the session -d.
  • screen -S my-session-name -X screen -t tab-name -m some-shell-command.
    • executes a command (-X) in our session called my-session-name.
      • The command executed is screen -t tab-name -m some-shell-command.
        • This calls the screen command to add a new tab called tab-name and run some-shell-command in that tab.
        • Commands are executed from the root of where screen is run, in our case this is the root of the monorepo.
  • yarn --cwd ./some-directory-in-my-project: I found that cd some-directory-in-my-project && yarn run some-script does not work in screen.
    • --cwd changes the working directory for yarn and makes it run against the specified directory.
  • screen -t scripts-1 -m sleep 1000; yarn --cwd ./chain run clean-migrate; yarn --cwd ./server run bulkinsert:
    • sleep 1000: After starting Ganache I've found you need to force the migration steps to wait to give Ganache enough time to start.
    • yarn --cwd ./chain run clean-migrate: As mentioned before I had issues using cd with screen and I could not work out how to get truffle to run from a specified path. A simple workaround was to add a script to the chain directory's package.json file which does this for me and use yarn to run it:
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "clean-migrate": "rm -fr build || true && truffle migrate"

.screenrc file to Make Screen More User-Friendly

To make screen more useable I use the following .screenrc file which I place in my home directory:

startup_message off
vbell off

hardstatus alwayslastline "%{=b}%{G} %{b}%w %=%{kG}%C%A %D,%d/%m/%y"
shelltitle "Shell"

# Window numbering starts at 1, not 0.
bind c screen 1
bind 0 select 10

# Look and feel
caption always "%{= 2m}%{+b w}Screen: %n | %h %=%t %D %d/%m/%y %c:%s"
hardstatus alwayslastline "%-Lw%{= BW}%50>%n%f* %t%{-}%+Lw%<  %=% [%{=b)%{Y}%l%{g}]"

# Left Right meta key mods
#  ALT-,. and ALT-<>
bindkey "^[<" eval number !echo $WINDOW-1|bc
bindkey "^[>" eval number !echo $WINDOW+1|bc
bindkey "^[," prev
bindkey "^[." next

select 1

termcapinfo xterm* ti@:te@


While screen is not necessarily the newest tool to run multiple things in different tabs I tend to use it as it is available on most Unix/Linux environments new and old. If it is not available it is almost certainly in the given environment's package manager and easy to install.