Linux Fu: Marker Is A Command Line Menu

The command line. You either love it or hate it, but if you do anything with a Unix-like system you are going to have to use it eventually. You might find marker — a system billed as a “command palette for the terminal” — a useful program to install. We couldn’t decide if it was like command history on steroids or more of a bookmark system. In a way, it is a little of both.

Your history rolls off eventually and also contains a lot of small commands (although you can use the HISTIGNORE variable to ignore particular commands). With marker, you save specific commands and they stay saved. There are no extra commands nor do the ones you save ever roll off.

Of course, you could just make a shell script or an alias if that’s all there was to it. Marker lets you add a description to the command and then you can search through the commands and the descriptions using a fuzzy incremental search. In addition, you can put placeholders into your command lines that are easily replaced. There are some built-in commands to get you started and the same bookmarks will work in bash and zsh, if you use both.

Installing Marker

Marker is a standalone project which you can install from its Github repo. Installation is easy and doesn’t require root. However, you still have to add a line to your shell initialization file, although it does give you instructions after the install. However, since the default keybindings may not work for you, you might want to just manually source it at first until you are happy with it. Then make the changes to your initialization file. In other words, you might want to wait before issuing the last two commands.

git clone --depth=1 https://github.com/pindexis/marker ~/.marker && ~/.marker/install.py
cp ~/.bashrc ~/.bashrc_backup
echo '[[ -s "$HOME/.local/share/marker/marker.sh" ]] && source "$HOME/.local/share/marker/marker.sh"' >> ~/.bashrc

Depending on your Linux distro there may be a gotcha that you also need to workaround. If typing part of a command and hitting CTRL-Space throws the error bash: bash_execute_unix_command: cannot find keymap for command you’ve encountered a known bug. Solved it by editing ~/.marker/bin/marker.sh according to these instructions. In fact, many of the keybindings may have problems on some systems. It is easier to just issue a “source” command in a shell to activate marker for that shell until you are sure you want to use it all the time:

source ~/.local/share/marker/marker.sh

Then if you get stuck, you can just exit that shell and open another one to recover. Once you are satisfied with your set up, you can follow the instructions to make the change to your .bashrc. Of course, you can always recover by copying .bashrc_backup to .bashrc if you followed the instructions above.

How to Use Marker

Take Marker for a spin by using it to search through your command history. If you’re accustomed to using CTRL-R to reverse search you’ll find this handy. By default you can type part of a command and hit CTRL-Space to search commands. Instead of hitting the keystroke repeatedly and seeing one line at a time (as with reverse search) you get a nice color coded list to select from!

When reusing commands you usually need to backtrack to the input and output files and change them for your needs, Marker will let you do this with CTRL-T. Each time you press it the cursor will move to the next placeholder — shown in double curly brackets — removing the placeholder automatically so you can just begin typing.

You also can write your own commands along with placeholders and use CTRL-K to bookmark them. This is where Marker gets much more powerful than reverse searching.

You can see a demo above, which shows off how the placeholder (like {{url}} in the example) scheme works. By default, the keys are Control+Space, Control+K, and Control+T, but those interfere with other bindings on my system, so I changed them in the script to Alt-., Alt-M, and Alt-P (more on that later). You can also override them by setting environment variables before you source the script ~/.marker/marker.sh.

Problems

You can control everything with the marker command instead of keystrokes. However, it is sometimes difficult to pick items. For example, I never got the “marker update” command to work. You can remove commands with “marker remove.”

The only significant problem I found was that there are a lot of built-in rules and many of them are rules I would not use. However, there’s no easy way to delete them. I’m sure I can go find where they live in the code and nuke them, of course, but it would be nice if you could delete them just like your own rules.

Here’s a tip: The code loads the files ~/.marker/tldr/common.txt and one other file that is OS-specific (e.g., linux.txt). By editing those files you can alter the default rules easily. Better still, copy what you want to ~/.local/share/marker/user_commands.txt and then move the old files out of the way so the defaults you want are there and you can change them or remove them.

I mentioned before the keystroke settings are not good for users that use emacs-style keybindings. There isn’t much documentation but at the top of marker.sh the script sets the three keys from the environment and provides default values. That’s where I changed the bindings. Obviously, you could set the environment variables, too. Here’s the code in question (with my changes):

# default key bindings
marker_key_mark="${MARKER_KEY_MARK:-\em}"
marker_key_get="${MARKER_KEY_GET:-\e.}"
marker_key_next_placeholder="${MARKER_KEY_NEXT_PLACEHOLDER:-\ep}"

The key names are what bind takes, which is poorly documented in general. The easiest way to figure it out is to do a “bind -P” and look how other keys work. In general, you can use Control keys like \C-t or keys with the \e prefix (typically Alt) as I did above. What documentation there is about this is in the bash manual under builtins.

In Practice

If you use the shell infrequently or you deal with super complex command lines this might be useful. We covered some other enhancements in an earlier installment of Linux Fu. By the way, if you add a lot of things to your bash startup and have more than one computer, you might enjoy my solution for using Git to manage and replicate your bash files.

21 thoughts on “Linux Fu: Marker Is A Command Line Menu

      1. Very *much* this. If bash+readline is your shell (which is almost 100% sure), CTRL-R (reverse search history) is it.

        Those proposing history | grep (I used that back then, when my shell was called Korn) didn’t even try CTRL-R. It rocks:

        – it doesn’t pollute your history with unnecessary “history | grep foo”
        – it is an *incremental* reverse search: start typing characters and the
        hits become more and more specific the longer your substring is

        Usually I reach my target with three to four keystrokes.

        And, oh — because it is libreadline, it will work as well with PostgreSQL’s client (psql), with R and with whatnot other interactive tools.

        1. The real use case of this tool isn’t search as much as providing searchable aliases with meaningful descriptions. So if you are trying ot remember the command line you used a year ago to renew your SSL certs, you can find it even though it is long gone from your history.

      1. You can arrange for all your shells to feed one history — which some people like (I do) and some don’t. This is the history part of my bash startup:

        # History Options
        # Don’t put duplicate lines in the history.
        export HISTCONTROL=”ignoredups:ignorespace”
        # Ignore some controlling instructions
        export HISTIGNORE=”[ ]*:&:bg:fg:exit”
        shopt -s histappend
        export PROMPT_COMMAND=”history -a; history -n; $PROMPT_COMMAND”

    1. I’ve started using a Jupyter notebook for repeated bash commands. It’s nice that you can put multiple commands in a cell, the out is saved and it’s easy to jump around between cells.

  1. If you want to get rid of the list from tldr, change line 61 in ~/.marker/marker/core.py from
    commands = command.load(get_user_marks_path()) + command.load(get_tldr_os_marks_path()) + command.load(get_t ldr_common_marks_path())
    to
    commands = command.load(get_user_marks_path())

  2. That drawing, it brought me here, even though the article series is interesting too.

    Man, i really wish i had 10% of that talent. Can’t even draw anywhere near acceptable car, and yes i want to draw cars (mine and others’).

  3. HISTIGNORE alone is worth the price of reading this entire article! Thanks, Al.

    The traditional way to “solve” the same problem that marker does is with alias or just by writing a small script for each. Sure, you have to remember the names of the scripts, but you can call your “get hackaday” script get_hackaday and you don’t lose much. Tab completion (see Al’s excellent article if you want to get fancy) and you’re done.

    Fuzzy search and a “bookmarks” file sound kinda cool though.

Leave a Reply

Please be kind and respectful to help make the comments section excellent. (Comment Policy)

This site uses Akismet to reduce spam. Learn how your comment data is processed.