You can do this using the python integration in gdb.
It would be nice if s ; bt stepped and then printed a backtrace, but it doesn't.
You can accomplish the same thing by calling into the Python interpreter.
python import gdb ; print(gdb.execute("s")) ; print(gdb.execute("bt"))
It's possible to wrap this up into a dedicated command, here called "cmds", backed by a python definition.
Here's an example .gdbinit extended with a function to run multiple commands.
# multiple commands
python
from __future__ import print_function
import gdb
class Cmds(gdb.Command):
  """run multiple commands separated by ';'"""
  def __init__(self):
    gdb.Command.__init__(
      self,
      "cmds",
      gdb.COMMAND_DATA,
      gdb.COMPLETE_SYMBOL,
      True,
    )
  def invoke(self, arg, from_tty):
    for fragment in arg.split(';'):
      # from_tty is passed in from invoke.
      # These commands should be considered interactive if the command
      # that invoked them is interactive.
      # to_string is false. We just want to write the output of the commands, not capture it.
      gdb.execute(fragment, from_tty=from_tty, to_string=False)
      print()
Cmds()
end
example invocation:
$ gdb
(gdb) cmds echo hi ; echo bye
hi
bye