Newer posts are loading.
You are at the newest post.
Click here to check if anything new just came in.

August 01 2013

18:45

Intro to Tmux

One of the most widely used tools in the web development process is surely the terminal. While you are working on a project, often you find yourself in the position of using the terminal with several tabs open at once, one for launching a local web server, a second tab for managing the database, another for copying files and so on. This can soon become messy and hard to handle. One solution for this problem which works well for me, is the terminal multiplexer, tmux.


What Is Tmux

tmux is a terminal multiplexer: it enables a number of terminals, each running a separate program to be created, accessed and controlled from a single screen.

The definition above, taken from the tmux website, is clear: from one terminal window we can start and control a number of other terminals and in each of them run a different application or a different instance of an application.

tmux is developed on a client-server model. This brings into the game the concept of sessions. A session is stored on the server which holds the representation of a window. Each window can be linked to multiple sessions and moved between them.

On the other hand, multiple clients can be attached to each session. So, one or more users can connect to a tmux session from different computers and they share the same information on the window. This is extremely useful in teaching or collaborating since the users sharing a tmux session see the same information on their terminal windows.

Connecting to a tmux session is done by starting the application with the following command:

tmux attach <session_name>

When one user wants to end the terminal sharing feature, the following command is used:

tmux detach

How to Install Tmux

tmux runs on Linux and Mac. At the moment of writing this article, I am not aware of a Windows version of the application.

For the majority of Linux distributions, there is a package in their repositories:

On Arch (which I use), installation is simply a matter of running the following command:

sudo pacman -S tmux

After installation, you can start tmux by issuing the command tmux in a terminal window. If you want to have it running automatically for each terminal session, a small bit of configuration is needed:

  • In the Settings menu go to Edit Current Profile and set the Command field to tmux as in the screenshot below:
tmux settings

If you are on Mac, iTerm2 comes with tmux installed, and to start it, you should issue the command: tmux.


Features

After installation, if you start a terminal window, the only new thing you’ll notice is the presence of a status line at the bottom of the screen:

terminal with tmux

Let’s take a look at the most common features. For a list of complete features, see the links at the end of this article.

Creating Panes

Or, in other words, splitting the main window. First of all, I must say that each tmux command is prefixed using the following key combination: <Ctrl-b>. This can be changed, but we will learn how to configure and customize tmux later on.

So, in order to split a window vertically (or in right and left panes) the following command should be used:

<Ctrl-b>%

and to split the window in horizontal panes you can use:

<Ctrl-b>"

And the result should look like following:

splitting windows

Moving From One Pane to Another and Positioning Panes

In order to move the cursor from one pane to the other (activating panes), the arrow keys are used. The command looks like this:

<Ctrl-b>[Up, Down, Right, Left]

If you want to go to the previously active pane, you can use the following command:

<Ctrl-b>;

Also, if you are not satisfied with the position of a pane, you can rotate the panes using the command:

<Ctrl-b><Ctrl-o>

Resizing Panes

Once created, you can change each panes size, in one cell step, using:

<Ctrl-b><Ctrl-Up[Down][Left][Right]>

or in five cells step using:

<Ctrl-b><Meta-Up[Down][Left][Right]>

Closing a Pane

When you want to close the current pane you can use:

<Ctrl-b>x

Create a New Window

Sometimes you may want to create another window, for example, to work on another project. This window might contain a completely different set of panes with different programs in each of them. To do so, issue the following command:

<Ctrl-b>c

Then if you want to switch to the next window you can use:

<Ctrl-b>n 

And you can switch to the previous window by using:

<Ctrl-b>p

Or you might select the window interactively with:

<Ctrl-b>w

Closing a Window

In order to close the currently opened window, you use:

<Ctrl-b>&

Copy Mode

Suppose you have issued a command on the terminal and the output of the command does not fit in one screen, so you’ll need to scroll up in order to see the entire output. If you try pressing the Up key, this won’t scroll you up, as it will only show you your command history. To scroll up the screen, use the following command:

<Ctrl-b>[

And then hit one of the following keys: Up, Down, PgUp or PgDn to scroll up or down.

Also, when in this mode you can copy text from the history and then paste it with:

<Ctrl-b>]

In order to exit this insert mode, just hit esc.

Now there are a lot of other commands bound to various keys. You can list all of the key bindings by issuing:

<Ctrl-b>?

Configuring Tmux

tmux is highly configurable. The configuration file is either /etc/tmux.conf for system wide settings or (recommended) ~/.tmux.conf for user specific settings.

Change the Prefix Key

One of the first things that most users change is the mapping of the prefix key (since <Ctrl-b> doesn’t seem to be so handy). Most users change it to <Ctrl-a>. This can be done like so:

set -g prefix C-a
unbind C-b
bind C-a send-prefix

The -g option in the first command tells tmux that this is a global option, meaning this is set for all windows and sessions.

Change the Key Bindings

Some users may prefer Vi or Emacs like bindings for the key actions. This is done using:

set -g status-keys vi
setw -g mode-keys vi

The setw command, sets the option for the window (affects all the panes in a window).

Status Line

You can perform various configurations of the status line: you can turn it on or off, you can change its background and foreground color, you can change what information is displayed inside it, etc.

To turn the status bar off, issue the following command:

set -g status off

Or you may try something like this:

set -g status-bg blue
set -g status-fg white
setw -g status-left #H:#S at #W:#T

… which changes the status line background to blue, the text color to white and displays to the left of the status bar the hostname of localhost, followed by a colon and the session name followed by the ‘at’ string and the window name, a colon, and lastly the pane title.

You can also display the status line at the bottom or at the top of the window:

set -g status-position [bottom | top]

For further information on configuration and other configuration options you can check the options section of the manual.


Conclusion

I hope you have found this introduction to tmux helpful in improving your terminal workflow. I’ve presented here just a few commands that I use most frequently. If you want to learn more, there are several resources that are available. I highly recommend:

April 19 2013

21:27

Writing a Shell Script From Scratch

Writing shell scripts can be rather daunting, primarily because the shell isn't the most friendly of languages to use. However, I hope to show you in this tutorial that shell scripting is actually not as tough or as scary as you might expect.

For this tutorial, we'll write a script that makes the process of using the Jasmine test framework a little bit easier. Actually, I wouldn't use this script today; I would use Grunt.js or something similar. However, I wrote this script before Grunt was around, and I found that writing it proved to be an excellent way to get more comfortable with shell scripting, so that's why we're using it.

One note: this tutorial is loosely associated with my upcoming Tuts+ Premium course, "Advanced Command Line Techniques." To learn more about pretty much anything in this tutorial, stay tuned for that course’s release. Hereafter in this tutorial, it will be referred to as "the course."

So, our script, which I call jazz, will have four main features:

  • It will download Jasmine from the web, unzip it, and delete the sample code.
  • It will create JavaScript files and their associated spec files, and pre-fill them with a bit of template code.
  • It will open the tests in the browser.
  • It will display the help text, which outlines the above.

Let's begin with the script file.


Step 1 - Creating the File

Writing a shell script is only useful if you can use it from the terminal; to be able to use your custom scripts on the terminal, you need to put them in a folder that is in your terminal's PATH variable (you can see your PATH variable by running echo $PATH). I've created a ~/bin folder (where ~ is the home directory) on my computer, and that's where I like to keep custom scripts (if you do the same, you'll have to add it to your path). So, just create a file, called jazz, and put it in your folder.

Of course, we'll also have to make that file executable; otherwise, we won't be able to run it. We can do this by running the following command:

    chmod +x jazz

Now that we can actually execute the script, let's add a very important part. All shell scripts should begin with a shebang). As Wikipedia says, this should be the first line of the script; it states what interpreter, or shell, this script should be run with. We're just going to use a basic, standard shell:

    #!/bin/sh

All right, with all that set up, we're ready to start writing the actual code.


Step 2 – Outlining the Script Flow

Earlier, I pointed out what the different features of our shell script should be. But how will the script know which feature to run? We'll use a combination of a shell parameter and a case statement. When running the script from the command line, we'll use a sub-command, like this:

    jazz init
    jazz create SomeFile
    jazz run
    jazz help

This should look familiar, especially if you've used Git:

    git init
    git status
    git commit

Based on that first parameter (init, create, run, help), our case statement will decide what to run. However, we do need a default case: what happens if no first parameter is given, or we get an unrecognized first parameter? In those cases, we'll show the help text. So, let's get started!


Step 3 – Writing the Help Text

We begin with the if statement that checks for our first parameter:

    if [ $1 ]
    then
        # do stuff 
    else
        # show help
    fi

You might be a little confused at first, because a shell if statement is pretty different from a "regular" programming language's if statement. To get a better understanding of it, watch the screencast on conditional statements in the course. This code checks for the presence of a first parameter ($1); if it's there, we'll execute the then code; else, we'll show the help text.

It's a good idea to wrap the printing of the help text in a function, because we need to call it more than once. We do need to define the function before it is called, so we'll put it at the top. I like this, because now, as soon as I open the file, I see the documentation for the script, which can be a helpful reminder when returning to code you haven't seen in a while. Without further ado, here's the help function:

    function help () {
        echo "jazz - A simple script that makes using the Jasmine testing framework in a standalone project a little simpler."
        echo "
        echo "    jazz init                  - include jasmine in the project";
        echo "    jazz create FunctionName   - creates ./src/FunctionName.js ./spec/FunctionNameSpec.js";
        echo "    jazz run                   - runs tests in browser";
    }

Now, just replace that # show help function with a call to the help function.

    else
        help
    fi


Step 4 – Writing the Case Statement

If there is a first parameter, we need to figure out which it is. For this, we use a case statement:

	case "$1" in
		init)
		
		;;
		create)
		
		;;
		run)
		
		;;
		*)
			help
		;;
	esac

We pass the first parameter to the case statement; then, it should match one of four things: "init", "create", "run", or our wildcard, default case. Notice that we don't have an explicit "help" case: that's just our default case. This works, because anything other than "init", "create", and "run" aren't commands we recognize, so it should get the help text.

Now we're ready to write the functional code, and we'll start with jazz init.


Step 5 – Preparing Jasmine with jazz init

All the code we write here will go within our init) case, from the case statement above. The first step is to actually download the standalone version of Jasmine, which comes in a zip file:

    echo "Downloading Jasmine ..."
    curl -sO $JASMINE_LINK

We first echo a little message, and then we use curl to download the zip. The s flag makes it silent (no output) and the O flag saves the contents of the zip to a file (otherwise, it would pipe it to standard out). But what's with that $JASMINE_LINK variable? Well, you could put the actual link to the zip file there, but I prefer to put it in a variable for two reasons: first, it keeps us from repeating part of the path, as you'll see in a minute. Second, with that variable near the top of the file, it makes it easy to change the version of Jasmine we're using: just change that one variable. Here's that variable declaration (I put it outside the if statement, near the top):

    JASMIME_LINK="http://cloud.github.com/downloads/pivotal/jasmine/jasmine-standalone-1.3.1.zip"

Remember, no spaces around the equals-sign in that line.

Now that we have our zip file, we can unzip it and prepare the contents:

    unzip -q <code>basename $JASMINE_LINK</code>
    rm -rf <code>basename $JASMINE_LINK</code> src/*.js spec/*.js

In two of these lines, we're using basename $JASMINE_LINK; the basename command just reduces a path to the base name: so path/to/file.zip becomes just file.zip. This allows us to use that $JASMINE_LINK variable to reference our local zip file.

After we unzip, we'll delete that zip file, as well as all the JavaScript files in the src and spec directories. These are the sample files that Jasmine comes with, and we don't need them.

Next, we have a Mac-only issue to deal with. By default, when you download something from the internet on a Mac, when you try to run it for the first time, you'll be asked to confirm that you want to run it. This is because of the extended attribute com.apple.quarantine that Apple puts on the file. We need to remove this attribute.

    if which xattr > /dev/null && [ "<code>xattr SpecRunner.html</code>" = "com.apple.quarantine" ]
    then
        xattr -d com.apple.quarantine SpecRunner.html
    fi

We begin by checking for the presence of the xattr command, because it doesn't exist on some Unix systems (I'm not sure, but it may be a Mac-only program). If you watched the course screencast on conditionals, you'll know that we can pass any command to if; if it has an exit status of anything but 0, it's false. If which finds the xattr command, it will exit with 0; otherwise, it will exit with 1. In either case, which will display some output; we can keep that from showing by redirecting it to /dev/null (this is a special file that discards all data written to it).

That double ampersand is an boolean AND; it's there for the second condition we want to check. That is, does the SpecRunner.html have that attribute? We can simply run the xattr command on the file, and compare it's output to the string we're expecting. (We can't just expect the file to have the attribute, because you can actually turn this feature off in Mac OS X, and we'll get an error when trying to remove it if the file doesn't have the attribute).

So, if xattr is found and the file has the attribute, we'll remove it, with the d (for delete) flag. Pretty straightforward, right?

The final step is to edit SpecRunner.html. Currently, it contains scripts tags for the sample JavaScript files that we deleted; we should also delete those scripts tags. I happen to know that those script tags span lines 12 to 18 in the files. So, we can use the stream editor sed to delete those lines:

    sed -i "" '12,18d' SpecRunner.html
    echo "Jasmine initialized!"

The i flag tells sed to edit the file in place, or to save the output from the command to the same file we passed in; the empty string after the flag means that we don't want sed to back up the file for us; if you wanted that, you could just put a file extension in that string (like .bak, to get SpecRunner.html.bak).

Finally, we'll let the user know that Jasmine has been initialized. And that's it for our jazz init command.


Step 6 – Creating Files with jazz create

Next up, we're going to let our users create JavaScript files and their associated spec files. This portion of the code will go in the “create" section of the case statement we wrote earlier.

    if [ $2 ]
    then
        # create files
    else
        echo "please include a name for the file"
    fi

When using jazz create, we need to include a name for the file as the second parameter: jazz create View, for example. We'll use this to create src/View.js and spec/ViewSpec.js. So, if there isn't a second parameter, we'll remind the user to add one.

If there is a file name, we'll start by creating those two files (inside the then part above):

    echo "function $2 () {

}" > src/$2.js
    echo "describe('$2', function () {

});" > spec/$2Spec.js

Of course, you can put whatever you want into your src file. I'm doing something basic here; so jazz create View will create src/View.js with this:

function View () {

}

You could replace that first echo line with this:

    echo "var $2 = (function () {
	var $2Prototype = {

	};

	return {
		create : function (attrs) {
			var o = Object.create($2Prototype);
			extend(o, attrs);
			return o;
		}
 	};
}());" > src/$2.js

And then jazz create View will result in this:

    var View = (function () {
        var ViewPrototype = {
        
        };
    
        return {
            create : function (attrs) {
                var o = Object.create(ViewPrototype);
                extend(o, attrs);
                return o;
            }
        };
    }());

So, really, your imagination is the limit. Of course, you'll want the spec file to be the standard Jasmine spec code, which is what I have above; but you can tweak that however you like as well.

The next step is to add the script tags for these files to SpecRunner.html. At first, this might seem tricky: how can we add lines to the middle of a file programmatically? Once again, it's sed that does the job.

    sed -i "" "11a\
    <script src='src/$2.js'></script>\
    <script src='spec/$2Spec.js'></script>
    " SpecRunner.html

We start just like we did before: in-place edit without a backup. Then our command: at line 11, we want to append the two following lines. It's important to escape the two new-lines, so that they'll appear in the text. As you can see, this just inserts those two scripts tags, exactly what we need for this step.

We can end with some output:

    echo "Created:"
    echo "	- src/$2.js"
    echo "	- spec/$2Spec.js"
    echo "Edited:"
    echo "	- SpecRunner.html"

And that's jazz create!


Step 7 – Running the Specs with jazz run

The last step is to actually run the tests. This means opening the SpecRunner.html file in a browser. There's a bit of a caveat here. On Mac OS X, we can use the open command to open a file in it's default program; this won't work on any other OS, but that's the way I do it here. Unfortunately, there's no real cross-platform way to do this, that I know of. If you're using this script under Cygwin on Windows, you can use cygstart in place of open; otherwise, try googling "[your OS] shell script open browser" and see what you come up with. Unfortunately, some versions of Linux (at least Ubuntu, in my experience) have an open command that's for something completely different. All this to say, your mileage with the following may vary.

if [ "`which open`" = '/usr/bin/open' ] 
then
    open SpecRunner.html
else
    echo "Please open SpecRunner.html in your browser"
fi

By now, you know exactly what this does: if we have open, we'll open SpecRunner.html, otherwise, we'll just print a message telling the user to open the file in the browser.

Originally, that if condition looked like this:

if which open > /dev/null

As we did with xattr, it just checked for existence of open; however, since I found out that there's a different open command on Linux (even on my Ubuntu server, which can't even open a browser!), I figured it might be better to compare the path of the open program, since the Linux one is at /bin/open (again, at least on Ubuntu server).

All this extra wordiness about open might sound like an excuse for my lack of a good solution, it actually points out something important about the command line. Don't mistake understanding the terminal with understanding a computer's configuration. This tutorial, and the associated course, have taught you a little bit more about the Bash shell (and the Z shell), but that doesn't mean each computer you use will be configured the same; there are many ways to install new commands (or different versions of commands), as well as remove commands. Caveat developer.

Well, that's the entire script! Here it is again, all together:

    #! /bin/sh

    function help () {
        echo "jazz - A simple script that makes using the Jasmine testing framework in a standalone project a little simpler."
        echo ""
        echo "    jazz init                  - include jasmine in the project";
        echo "    jazz create FunctionName   - creates ./src/FunctionName.js ./spec/FunctionNameSpec.js";
        echo "    jazz run                   - runs tests in browser";
    }

    JASMIME_LINK="http://cloud.github.com/downloads/pivotal/jasmine/jasmine-standalone-1.3.1.zip"

    if [ $1 ] 
    then
      case "$1" in
      init)
        echo "Downloading Jasmine . . ."
        curl -sO $JASMIME_LINK 
        unzip -q `basename $JASMIME_LINK` 
        rm `basename $JASMIME_LINK` src/*.js spec/*.js
        
        if which xattr > /dev/null && [ "`xattr SpecRunner.html`" = "com.apple.quarantine" ]
        then
          xattr -d com.apple.quarantine SpecRunner.html
        fi

        sed -i "" "12,18d" SpecRunner.html
        echo "Jasmine initialized!"
      ;;
      create)
        if [ $2 ]
        then 
          echo "function $2 () {

}" > ./src/$2.js
          echo "describe('$2', function () {
it('runs');
});" > ./spec/$2Spec.js
          sed -i "" "11a\
          <script src='src/$2.js'></script>\
          <script src='spec/$2Spec.js'></script>
          " SpecRunner.html
          echo "Created:"
          echo "	- src/$2.js"
          echo "	- spec/$2Spec.js"
          echo "Edited:"
          echo "	- SpecRunner.html"
        else
          echo 'please add a name for the file'
        fi
      ;;
      "run")
        if [ "`which open`" = '/usr/bin/open' ] 
        then
          open ./SpecRunner.html
        else
          echo "Please open SpecRunner.html in your browser"
        fi
      ;;
      *)
        help;
      ;;
      esac
    else
      help;
    fi

Well, go on, give it a try!

    mkdir project
    cd project
    jazz init
    jazz create Dog
    # edit src/Dog.js and spec/DogSpec.js
    jazz run

By the way, if you want to have some more fun with this project, you can find it on Github.


Conclusion

So there you have it! We've just written an intermediate level shell script; that wasn't so bad, now, was it? Don’t forget to stay tuned for my upcoming Tuts+ Premium course; you'll learn a lot more about many of the techniques used in this article, as well as countless others. Have fun on the terminal!

Sponsored post
feedback2020-admin
04:05

February 16 2012

14:47

How to Customize Your Command Prompt

Lately, I’ve been getting this question a lot: “how did you get your terminal to look the way it does?” If you’ve noticed my terminal and are curious about how I set it up, this is the tutorial for you! Of course, what you learn here will be enough to get you started on creating your own custom command prompt, as well!


Before we get started, I want to make something extremely clear. I’m certainly a command line enthusiast, but I’m not at all a command line pro. I feel at home in a terminal, but I’m a far cry from knowing everything. So here’s the deal: I’m going to show you how I’ve set up my terminal, but that doesn’t mean I’ll be able to explain every single line of code we’ll look at. There are some things here that are the way they are just because that’s what works … and I don’t always 100% know why.

With that disclaimer out of the way, let’s see what we’re doing.


Meeting the Finished Product

Here’s what my command prompt looks like:

If you’re not sure what you’re looking at there, let me explain:

  • In the turquoise, we have the name of the computer; in my case, that’s mothership. That’s followed by a colon.
  • Next, we have the working directory, in a yellow-orange.
  • If we’re in a git repository, we have some info on that next. The main thing here is the branch name (master or tilt_in_post_class in the screenshot). Also, if the working directory is clean, that text appears in green; otherwise, it appears in red.
  • Finally, we have a battery indicator. If the ten triangles are all green and filled in, things are powered up. As my battery empties, the triangles will empty and eventually turn red. Of course, if you aren’t on a laptop like I am, this won’t be as useful to you.

Getting the Environment Ready

Let’s now get a few preliminary pieces together, before actually writing some shell scripts.

First, there’s the colour scheme. You might recognize it as Ethan Schoonover’s Solarized colour scheme. It’s pretty amazing, and I’ve used it on both the terminal and in Vim ever since I discovered it. If you want to use it in the Terminal, you’ll have to install the theme. The Terminal in Snow Leopard didn’t support xterm-256color, so you’ll have to follow some special directions on the Solarized GitHub page to get that working if you’re still on that OS.

If you’ve moved on to Lion, you can just install the .terminal files you’ll find in the xterm-256color folder. Once you have those installed (just double-click them), you should be able to select the one you want in the Terminal preferences. Don’t forget to set it as the default scheme.

The next thing to know is that I’m not using the default bash shell in my Terminal. Instead, I’ve switched to zsh, which is basically much bash-compatible, but has a few nice additions, like better tab completion. Here’s how to do it: open the Mac system preferences and go to “Users & Groups.” Unlock the pane by clicking the lock at the bottom and entering your password. Then, right-click on your user in the list and choose “Advanced Options.” In the “Login Shell” field, switch from /bin/bash to /bin/zsh. It’s that simple.

Fonts

Next step: get the right font. I’m using Inconsolata at 15pt. It’s a free monospace font that I love staring at all day long. (Besides using it in the Terminal, I use it in Vim and TextEdit.) You can set your default font from within the Terminal preferences, right where you choose the colour scheme.

Another small thing is the size of your window: Open Terminal Preferences > Settings and click the Window tab; part-way down, you can choose the number of columns and rows you want; I use 130 columns by 30 rows.

Battery

Remember the battery level indicator? Well, that requires a little script from developer Steve Losh; simply copy that into a file and save it as a python file; since ~/bin is in my terminal PATH, I’ve saved the file to ~/bin/batcharge.py. As he notes, this script will only work on Mac OS X, so if you’re running zsh on another system, you’ll have to leave this part out.

Zsh

Last, but most certainly not least, there’s oh-my-zsh. According to the Github repo, this is just “A handful of functions, auto-complete helpers, and stuff that makes you shout ‘OH MY ZSHELL!’”

Why use it? For me, I decided to give it a try at one point and I’ve left it installed. If you use the terminal a lot, poke around oh-my-zsh for a bit when you have some time. You might be surprised at what you’ll find. Installing oh-my-zsh is fairly simple: just follow the setup instructions in the README; they’re pretty straight-forward.

Now we have all the necessary parts in place. We’re ready to actually start creating our custom terminal.


Creating the Files

When you installed oh-my-zsh, it was installed to ~/.oh-my-zsh. Pop that open. You’ll see two folders of note: themes and templates. Inside templates, you’ll find a file called zshrc.zsh-template This is a template for you ~/.zshrc file. If you’ve customized your terminal before, you’ll know that the .bashrc file is where your customizations are stored when you’re using a bash shell. The .zshrc is that same thing, except for the zsh shell. So open up that template file; you don’t have to know what exactly is going on; after all, there are a lot of comments in the file that might not make sense. One thing here is important to use. Notice the line that says this:

ZSH_THEME="robbyrussell"

That’s the name of the theme your terminal is using. Look in the themes folder: you’ll see a robbyrussel.zsh-theme file. What we’re going to do is create a theme of our own, so you can replace that string with the name of our new file. I’ve uncreatively called mine ‘doubleend” because it’s got into on both sides of the terminal.

Any other customizations you want to make to your zsh environment can be made in this file. If you use the terminal a lot, check out oh-my-zsh‘s plugins (in the plugins folder): a ton of useful stuff in there.

Don’t forget to copy to zshrc.zsh-template to your home directory and rename it to .zshrc before you make your changes. Now, in the themes folder, create a file with the theme name you set in your .zshrc file. Make sure you give it the .zsh-theme extension. We’re ready to build our custom theme.


Building the Custom Theme

The most important thing in your theme file is the PROMPT variable. It’s contents is your command prompt. To get the idea of this, just start with this in your theme file:

PROMPT='myPrompt=>'

Open a new Terminal window and you should see this:

All right, let’s get to work. We’re going to have to write several functions, but we’ll start with the PROMPT variable. It might not be noticeable when looking at the terminal, but there are actually three lines to my prompt. The first is a blank line, just to give me some breathing room. The second has all the information, and the third has the arrow. That third line is where you actually type the command. So, here’s our start:

PROMPT='

$reset_color→ '

Yes, you can do multiline strings that easily in shell scripting. But what’s up with $reset_color? That’s a variable that oh-my-zsh defines for us; it resets the colour of the output. This requires a short diversion to discuss how we colour different words in the prompt. You see, there’s a code—a series of characters—that switch the following text to a colour. Obviously, there’s a code for each available colour. Don’t worry, there are other variables for the other colours; you don’t have to learn the codes. By the time we get to the third line, though, we want to reset that to the default text colour; so, we use the $reset_color variable.

If you’re curious about the arrow character, it’s the Unicode rightwards arrow (U+2192, &rarr;). That’s all.

So, now our prompt is looking like this:

Looking svelte. Let’s now add the computer name and working directory. This is all for that second line of our PROMPT variable.

$fg[cyan]%m: $fg[yellow]$(get_pwd) 

We start by setting the text colour to cyan; it appears that we’re getting that colour code from an associative array or hash; while I don’t use it, there’s a $bg hash which changes the background colour instead of the foreground (text) colour.

After setting the colour, we have %m this outputs the name of the computer. After the colon and space, we switch the text colour to yellow. Next, we use the dollar sign and parens to add the output of the function get_pwd. This will output our current working directory, we a bit of a twist. If I’m in the home directory, I don’t want to see /Users/andrew, I want to see ~ instead. So, here’s that function:

function get_pwd() {
	echo "${PWD/$HOME/~}"
}

The function shell is pretty straightforward if you’ve written JavaScript before; identical syntax. I’m not sure where that search-and-replace syntax originated, but that looks pretty similar to the Vim search-and-replace syntax: If PWD includes the text $HOME (a system variable for your home directory), replace it with ~.

Now, here’s what’s down:

Good! Now comes the tricky part. You see, I want to right-align the git information and the battery indicator. Since there’s no way to actually right-align, we have to count the number of characters of text we want, subtract that from the width of the window, and add that spacing. It’s pretty hacky, and the code is pretty messy, but it’s all I’ve been able to find that actually works.

Ready? We insert the spacing with a function that I call get_spacing. So add $(get_spacing) to the end of our second line, so it now looks like this:

$fg[cyan]%m: $fg[yellow]$(get_pwd)$(put_spacing)

Now, that function. Of course, here’s the shell:

function put_spacing() {

}

There are four parts inside. Here’s the first.

local git=$(git_prompt_info)
if [ ${#git} != 0 ]; then
    ((git=${#git} - 10))
else
    git=0
fi

We start by getting the output from the git_prompt_info function and storing it in a local variable, git. Next, if the length of that string is not 0, we reset git so that is now the length of the string minus 10. Otherwise, we reset git to 0. This doesn’t seem to make much sense, until you realize what we’re trying to do here. We want to find out how many character “slots” the git information takes up. The tricky part is that we’re reusing the variable git: first it holds the string, then it holds the number representing the number of characters our git info is long. If git is zero characters long, we set git to 0; if it isn’t (meaning we’re in a git repository), we set git to the number of characters in the string, minus 10. This is because the string character count includes the colour codes, which aren’t actually visible, so they don’t take up width. The double parens? Oh, they’re used for doing math.

We do the very same thing for the battery output:

local bat=$(battery_charge)
if [ ${#bat} != 0 ]; then
    ((bat = ${#bat} - 18))
else
    bat=0
fi

In the third part, we figure out how much spaces we’ll need:

local termwidth
(( termwidth = ${COLUMNS} - 3 - ${#HOST} - ${#$(get_pwd)} - ${bat} - ${git} ))

A bit more math: we start with COLUMNS, which is the number of characters the Terminal is wide. We subtract all the appropriate values (the 3 is for two spaces and a colon), and we end up with the fact that we need termwidth number of spaces between the left and right parts of the prompt.

Now, let’s create a string that’s termwidth number of spaces long:

local spacing=""
for i in {1..$termwidth}; do
    spacing="${spacing} "
done
echo $spacing

A simple for-in loop allows us to create the string; then, we return it.

You can’t really tell that the whitespace has been added, so I’ve added some dummy text so you can see that’s it’s been added.

Next up, the Git info. We add $(git_prompt_info) to the end of prompt line 2; as you know, that’s a function call.

$fg[cyan]%m: $fg[yellow]$(get_pwd)$(put_spacing)$(git_prompt_info)

Notice that we don’t change the colour before loading the Git info: the function will take care of that, because it depends on the repository status.

And here’s the function:

function git_prompt_info() {
	ref=$(git symbolic-ref HEAD 2> /dev/null) || return
	echo "$(parse_git_dirty)$ZSH_THEME_GIT_PROMPT_PREFIX$(current_branch)$ZSH_THEME_GIT_PROMPT_SUFFIX"
}

The first line just checks to see if we’re in a Git repository. If we aren’t we return. If we are, the next line echos out the right info. Notice two things here: first, we’re using two variables: $ZSH_THEME_GIT_PROMPT_PREFIX and $ZSH_THEME_GIT_PROMPT_SUFFIX. I’ll show you how these are defined in a second. The other thing is two other functions that are called. These are provided by oh-my-zsh. The current_branch function just returns the current branch. The parse_git_dirty is more interesting, though. If the current branch is dirty (has uncommitted changes), the function will output the $ZSH_THEME_GIT_PROMPT_DIRTY; otherwise it will output $ZSH_THEME_GIT_PROMPT_CLEAN.

I have these four variables defined like so:

ZSH_THEME_GIT_PROMPT_PREFIX="[git:"
ZSH_THEME_GIT_PROMPT_SUFFIX="]$reset_color"
ZSH_THEME_GIT_PROMPT_DIRTY="$fg[red]+"
ZSH_THEME_GIT_PROMPT_CLEAN="$fg[green]"

Based on these variables, a repo on a clean master branch will output [git:master] in green; a dirty master branch will output +[git:master].

And lastly, we call the battery_charge function:

$fg[cyan]%m: $fg[yellow]$(get_pwd)$(put_spacing)$(git_prompt_info) $(battery_charge)

Here’s the battery_charge function:

function battery_charge() {
    if [ -e ~/bin/batcharge.py ]
    then
        echo `python ~/bin/batcharge.py`
    else
        echo '';
    fi
}

If the file exists, we run that file and echo the output. Notice that we use the backticks around the running of the file (those aren’t single quotes): this allows us to execute a string of code as if it was in the terminal. If the file doesn’t exist, we just echo an empty string.

And with that, we’re done! Here’s what we end with:


Conclusion

Well, that’s what my terminal looks like. I’ve forked the oh-my-zsh project on GitHub and added this theme, so you can find it there. If you’re interested in seeing my other dotfiles, I’ve got them on GitHub too.

However, I’m not done with my command line setup yet. While I haven’t made any changes in a while, I’m thinking of including the current user’s name (because I use this same theme on my server), and also some RVM info. Also, I’m not sure why I have the word git in there; I guess I originally had a setup that worked with multiple version control systems … Anyway, the point of all this is that this is something you’ll continually be tweaking. When I make changes, I’ll be sure to push them to GitHub, so you’ll be able to see them there.

Let me leave you with several links that you’ll find useful in hacking around on the command line:

Have fun!


June 20 2011

15:43

How to Customize the Command Prompt

Advertise here

I’m a big fan of the terminal: whether you’re leveraging a handful of commands (or more!) to improve your development process, or just using it to quickly move around your drives and open files and folders, the command line is an awesome tool. However, if you use it often, you’ll want to customize it to your needs. I’ll show you how to do that today!

I’m often asked, “How did you get your command prompt to look like that?” Well, in this tutorial, I’ll show you exactly how to do it. It’s pretty simple, and won’t require too much of your time.

I should note that what I’m showing you is specifically for the bash shell; this is the default shell on Mac and most Linux systems. If you’d like a bash prompt on Windows, you might want to check out Cygwin.


How does it Work?

Before we get started, let’s talk for a minute about how you customize your bash prompt. It’s not quite the same as you’re average application: there’s no preferences panel. Your customizations are stored in a file. If you’re on Linux (or using Cygwin), that will be your .bashrc file; on Mac, that’s your .bash_profile file. In both cases, this file is kept in your home directory (if you aren’t sure where that is for a Cygwin install, run the command echo $HOME). Note that I’ll only refer to the .bashrc file from here on out, but use the .bash_profile if you’re on a Mac.

Note that on Macs (and possibly Linux machines; I’m not sure), files that begin with a period are hidden by default. To show them, run these two lines in the terminal

defaults write com.apple.finder AppleShowAllFiles TRUE
killall Finder

So, what goes in that .bashrc file? Each line is actually a command that you could run on the command line. In fact, that’s how these config files work: When you open the console, all the commands you’ve written in the config file are run, setting up your environment. So, if you just want to try out some of what I’ll show below, just type it on the command line itself. The simplicity here is beautiful.


Customizing PS1

Let’s start with a definition. The prompt is what you see at the beginning of the line, each time you hit enter on the command line. Here’s what the default settings are for the Mac:

Mac Default Terminal

In this case, the prompt is andrews-macbook:~ screencast$. There’s a few variables here: andrew-macbook is the name of this computer, ~ is the current directory (the home directory) and screencast is the username. Let’s customize this a bit.

Open up either your .bashrc file. The way we set what information is displayed in the prompt is with the PS1 variable. Add this to the file:

PS1='->'

Notice that I don’t put spaces on either side of the equals sign; that’s necessary. Save this file in your home directory and re-open a terminal window. Now, you should have a prompt that looks like this:

Mac Customized Terminal

I’ll note here that if you find it tedious to close and re-open your terminal each time you make a change to your .bashrc or .bash_profile, there’s a bit of a shortcut: You can load any bash customization file with the source command. Run this in your terminal:

source ~/.bashrc 

Still too long? Well, a single period (.) is an alias for source. Happy now? If you’re quick, you’ll realize that we can use the source command to include other files within our .bashrc file, if you want to split it up to keep in under control.

Let’s customize our prompt a bit more. We can use built-in variables in the string we assign to PS1 to include helpful information in the prompt; here’s a few useful one:

  • \d: Date
  • \h: Host
  • \n: Newline
  • \t: Time
  • \u: Username
  • \W: Current working directory
  • \w: Full path to current directory

So, if you set your prompt to this:

PS1='\n\W\n[\h][\u]->'

you should see something like this:

Mac Customized Terminal

Notice a few things here: firstly, we’re using a bunch of the variables shown above to give us more information. But secondly, we’re including a few newlines in there, and getting a more interesting prompt: we have the current directory on one line, and then the actual prompt on the next line. I prefer my prompt this way, because I always have the same amount of space to write my commands, no matter how long the path to the current directory is. However, there’s a better way to do this, so let’s look at that now.


Customizing PROMPT_COMMAND

The better way to do this is the use the PROMPT_COMMAND variable; the contents of this variable isn’t just a string, like with PS1. It’s actually a command that executed before bash displays the prompt. To give this a try, let’s add this to our .bashrc:

PROMPT_COMMAND='echo "comes before the prompt"'

We’re using the echo command here; if you aren’t familiar with it, you just pass it a string, and it will write it to the terminal. By itself, it’s not incredibly useful (although you can use it to view variables: echo $PS1), but it’s great when used with other commands, so display their output. If you added the line above, you should see this:

Mac Customized Terminal

Let’s do something more useful here. Let’s write a bash function that we will assign to PROMPT_COMMAND. Try this:

print_before_the_prompt () {
    echo "comes before the prompt"
}

PROMPT_COMMAND=print_before_the_prompt

If you use this, you shouldn’t see a difference in your prompt from what we have above. Now, let’s make this useful.

print_before_the_prompt () {
  echo "$USER: $PWD"
}

PROMPT_COMMAND=print_before_the_prompt

PS1='->'

Here’s what you’ll get:

Mac Customized Terminal

That’s a good start, but I want to do a bit more. I’m going to use the printf command instead of echo because it makes including newlines and variables a bit easier. A quick background on the printf command: it takes several paramters, the first being a kind of template for the string that will be outputted. The other parameters are values that will be substituted into the template string where appropriate; we’ll see how this works.

So let’s do this:

print_before_the_prompt () {
    printf "\n%s: %s\n" "$USER" "$PWD"
}

See those %s parts in there? That means “interpret the value for this spot as a string”; for context, we could also use %d to format the value as a decimal number. As you can see, we have two %ss in the “template” string, and two other parameters. These will be placed into the string where the %ss are. Also, notice the newlines at the beginning and end: the first just gives the terminal some breathing room. The last one makes sure that the prompt (PS1) will be printed on the next line, and not on the same line as PROMPT_COMMAND.

You should get a terminal like this:

Mac Customized Terminal

Adding Some Color

Looking good! But let’s take it one step farther. Let’s add some color to this. We can use some special codes to change the color of the text in the terminal. It can be rather daunting to use the actual code, so I like to copy this list of variables for the color and add it at the top of my .bashrc file:

txtblk='\e[0;30m' # Black - Regular
txtred='\e[0;31m' # Red
txtgrn='\e[0;32m' # Green
txtylw='\e[0;33m' # Yellow
txtblu='\e[0;34m' # Blue
txtpur='\e[0;35m' # Purple
txtcyn='\e[0;36m' # Cyan
txtwht='\e[0;37m' # White

bldblk='\e[1;30m' # Black - Bold
bldred='\e[1;31m' # Red
bldgrn='\e[1;32m' # Green
bldylw='\e[1;33m' # Yellow
bldblu='\e[1;34m' # Blue
bldpur='\e[1;35m' # Purple
bldcyn='\e[1;36m' # Cyan
bldwht='\e[1;37m' # White

unkblk='\e[4;30m' # Black - Underline
undred='\e[4;31m' # Red
undgrn='\e[4;32m' # Green
undylw='\e[4;33m' # Yellow
undblu='\e[4;34m' # Blue
undpur='\e[4;35m' # Purple
undcyn='\e[4;36m' # Cyan
undwht='\e[4;37m' # White

bakblk='\e[40m'   # Black - Background
bakred='\e[41m'   # Red
badgrn='\e[42m'   # Green
bakylw='\e[43m'   # Yellow
bakblu='\e[44m'   # Blue
bakpur='\e[45m'   # Purple
bakcyn='\e[46m'   # Cyan
bakwht='\e[47m'   # White

txtrst='\e[0m'    # Text Reset

There’s some method to this madness: The first set are turn on normal coloring. The second set turn on bold coloring. The third set turn on underlined coloring. And that fourth set turn on background coloring. That last one resets the coloring to normal. So, let’s use these!

print_before_the_prompt () {
    printf "\n $txtred%s: $bldgrn%s \n$txtrst" "$USER" "$PWD"
}

Here, I’ve added $txtred before the first %s, and $bldgrn before the second %s; then, at the end, I’ve reset the text color. You have to do this because once you set a color, it will hold until you either use a new color or reset the coloring. You’ll also notice that when setting a variable, we don’t prefix it with a dollar sign; but we do use the dollar sign when using the variable: that’s the way bash variables work. This gives us the following:

Mac Customized Terminal

Let’s move on to the final step: adding some scripting to give us even more information.


Adding Version Control Information

If you’ve seen the screencasts that come with my book Getting Good with Git (yes, a shameless plug), you might remember that I have some version control information showing in my prompt. I got this idea from the excellent PeepCode “Advanced Command Line” screencast, which share this, as well as many other great tips.

To do this, we’re going to need to download and build the script that finds this information. Head on over to the repository for vcprompt, a script that outputs the version control information. If you’re familiar with the Mercurial version control system, you can use that to get the repo, but you’ll most likely want to hit that ‘zip’ link to download the script code as a zip file. Once you unzip it, you’ll have to build the script. To do this, just cd into the unzipped script folder and run the command make. Once this command runs, you should see a file named ‘vcprompt’ in the folder. This is the executable script.

So, how do we use this in our prompt? Well, this brings up an important rabbit-trail: how do we “install” a script (like this one) so that we can use it in the terminal? All the commands that you can run on the terminal are found in a defined array of folders; this array is the PATH variable. You can see a list of the folders currently in your PATH by running echo $PATH. It might look something like this:

/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin

What we need to do is put the executable script vcprompt in a folder that’s in our path. What I like to do (and yes, I learned this trick from that PeepCode screencast, too) is create a folder called ‘bin’ (short for ‘binary’) in my home directory and add that folder to my PATH. Add this to your .bashrc:

export PATH=~/bin:$PATH

This sets PATH to ~/bin, plus whatever was already in the PATH variable. If we now put that vcprompt script into ~/bin, we will be able to execute it in any folder on the terminal.

So, now let’s add this to our prompt:

print_before_the_prompt () {
    printf "\n $txtred%s: $bldgrn%s $txtpur%s\n$txtrst" "$USER" "$PWD" "$(vcprompt)"
}

I’ve added $txtpur %s to the “template” string, and added the fourth parameter"$(vcprompt)". Using the dollar sign and parenthesis will execute the script and return the output. Now, you’ll get this:

Mac Customized Terminal

Notice that if the folder doesn’t use some kind of version control, nothing shows. But, if we’re in a repository, we get the version control system that’s being used (Git, in my case) and the branch name. You can customize this output a bit, if you’d like: check the Readme file that you downloaded with the source code for the vcprompt script.


Moving On!

Here’s our complete .bashrc or .bash_profile file:

export PATH=~/bin:$PATH

txtblk='\e[0;30m' # Black - Regular
txtred='\e[0;31m' # Red
txtgrn='\e[0;32m' # Green
txtylw='\e[0;33m' # Yellow
txtblu='\e[0;34m' # Blue
txtpur='\e[0;35m' # Purple
txtcyn='\e[0;36m' # Cyan
txtwht='\e[0;37m' # White
bldblk='\e[1;30m' # Black - Bold
bldred='\e[1;31m' # Red
bldgrn='\e[1;32m' # Green
bldylw='\e[1;33m' # Yellow
bldblu='\e[1;34m' # Blue
bldpur='\e[1;35m' # Purple
bldcyn='\e[1;36m' # Cyan
bldwht='\e[1;37m' # White
unkblk='\e[4;30m' # Black - Underline
undred='\e[4;31m' # Red
undgrn='\e[4;32m' # Green
undylw='\e[4;33m' # Yellow
undblu='\e[4;34m' # Blue
undpur='\e[4;35m' # Purple
undcyn='\e[4;36m' # Cyan
undwht='\e[4;37m' # White
bakblk='\e[40m'   # Black - Background
bakred='\e[41m'   # Red
badgrn='\e[42m'   # Green
bakylw='\e[43m'   # Yellow
bakblu='\e[44m'   # Blue
bakpur='\e[45m'   # Purple
bakcyn='\e[46m'   # Cyan
bakwht='\e[47m'   # White
txtrst='\e[0m'    # Text Reset

print_before_the_prompt () {
    printf "\n $txtred%s: $bldgrn%s $txtpur%s\n$txtrst" "$USER" "$PWD" "$(vcprompt)"
}

PROMPT_COMMAND=print_before_the_prompt
PS1='->'

Well, that’s a crash-course on customizing your bash prompt. If you have any questions, be sure to drop them in the comments!

April 18 2011

14:57

The Perfect Workflow, with Git, GitHub, and SSH


In this lesson, we’ll focus on workflow. More specifically, we’ll use the helpful GitHub service hooks to automatically update a project on our personal server whenever we push updates to a GitHub repo.


Prefer a Video Tutorial?

Press the HD for a clearer picture.
Subscribe to our YouTube and Blip.tv channels to watch more screencasts.

Step 1 - Create a Git Repo

We certainly need some sort of project to play around with, right? Let’s do that right now. Using which ever tool you prefer (I’d recommend Structurer), create a new directory, called awesomeProject, and add an index.html file. Feel free to populate this with some gibberish markup for the time being.

With our test directory in place, let’s create our first Git commit.

If you’re unfamiliar with Git, I highly recommend that you first review “Easy Version Control with Git.”

Open the command line:

cd path/to/awesomeProject
git init
git add .
git commit -m 'First commit'

Those familiar with Git should feel right at home. We’re creating a Git repo, adding all the files to the staging area, and are then creating our first commit.


Step 2 - Uploading to GitHub

The next step is to upload our project to GitHub. That way, we can easily call a git pull to download this project from any computer/server we wish.

Again, if you’re not familiar with GitHub, and haven’t yet created an account, read Terminal, Git, and GitHub for the Rest of Us.

Begin by creating a new Git repository.

Create a Git Repo

Next, you’ll need to fill in some details about your project. That’s simple:

Details

And finally, since we’re already working with an existing Git repo, we only need to run:

git remote add origin git@github.com:Your-Username/awesomeProject.git
git push -u origin master
Git

With that out of the way, our awesomeProject is now available on GitHub. That was easy!


Step 3 - SSH

Now, we certainly need some sort of live preview for our project, ideally stored on our own server. But this can be a pain sometimes. Push your updates to GitHub, login to your server, manually transfer the updated directory, etc. Granted, this only takes a moment or so, but when you make multiple changes through out the day, this can quickly become a burden.

But one step at a time. We’ll tackle this dilemma in Step 4. For now, let’s simply pull in our Git repo to our server. To do so, we need to SSH in.

Depending upon your host, your SSH credentials will vary slightly. Search Google for “your-host-name SSH,” and you’ll surely find the necessary instructions. Once you’re ready, let’s move along:

We’ll use my personal server as an example:

ssh jeffrey-way.com@jeffrey-way.com
<enter your host password>

And with those two lines, we’re in!

SSH

Next, we cd to the parent directory of where we wish to store awesomeProject. For me, this will be: cd domains/demo.jeffrey-way.com/html/. Of course, modify this according to your own directory structure.

Git Clone

Let’s clone the GitHub repo now.

git clone git@github.com:Your-User-Name/awesomeProject.git

Give that command a few seconds, but, before you know it, that directory is now available on your server, and, in my case, could be viewed at: http://demo.jeffrey-way.com/awesomeProject.


Step 4 - Creating a Connection

The inherent problem at this point is that there’s no specific connection between our GitHub repo and the directory stored on our server — at least not an automated connection. For example, if we update our source files on our local machine, and then push the changes to GitHub:

git add index.html
git commit -m 'Added photo of dancing chicken'
git push origin master

These changes will certainly not be reflected on our server. Of course they won’t! In order to do so, we must – once again – SSH into our server, cd to the awesomeProject directory, and perform another git pull to bring in the updated source files.

Wouldn’t it be great if, every time we pushed updates to GitHub, those new source files were automatically updated on our live preview server?

As it turns out, we can do this quite easily with GitHub service hooks.

GitHub Service Hooks

You can access this page by pressing the “Admin” button from within your GitHub repo, and then clicking “Service Hooks.” The “Post-Receive URL” option will instruct GitHub to send a POST request to the specified page every time you push to your GitHub repo. This is exactly what we need!

“We’ll hit these URLs with POST requests when you push to us, passing along information about the push.”

To make this work, we’ll need to create one more file that will handle the process of performing the git pull. Add a new file, called github.php (or anything you wish – preferably more vague), and add:

<?php `git pull`;

So now you’re thinking: “Jeff’s gone crazy. You can’t put a Bash script into a PHP string.” Well…yes you can, once you realize that those aren’t single quotes above, they’re back-ticks.

When you wrap a sequence in back-ticks, in PHP, it’ll be treated as a Bash script. In fact, it’s identical to using the bash_exec function.

Save that file, and upload it to the awesomeProject directory on your server. When finished, copy the url to that file, and paste it into the “Post-Receive URL” textbox. In my case, the url would be http://demo.jeffrey-way.com/awesomeProject/github.php.

With this in place, every single time you push to your GitHub repo, that file will be called, and the awesomeProject directory on your server will auto-update, without you needing to move a finger. Pretty nifty, ay?


You Also Might Enjoy:

March 16 2011

22:16

Speed up your Workflow in the Terminal: New Premium Tutorial


The terminal is great, especially for web development, but typing out long, obscure commands and directories deep in the filesystem can get tedious. Aliases and functions allow you to create short, memorable names for commands you type all the time. In this Premium video tutorial, we will learn how to create and use both of these to speed up your command line workflow.

Sign up for Tuts Premium to view this tutorial, as well as hundreds of other advanced tutorials and screencasts.


Join Net Premium

NETTUTS+ Screencasts and Bonus Tutorials

For those unfamiliar, the family of Tuts+ sites runs a premium membership service. For $9 per month, you gain access to exclusive premium tutorials, screencasts, and freebies from Nettuts+, Psdtuts+, Aetuts+, Audiotuts+, Vectortuts+, and CgTuts+ For the price of a pizza, you’ll learn from some of the best minds in the business. Become a Premium member to read this tutorial, as well as hundreds of other advanced tutorials and screencasts.

September 06 2010

12:58

10 Terminal Commands That Will Boost Your Productivity


Back in May, Nettuts+ ran a great article entitled ”7 Simple and Useful Command-Line Tips”; this was a great article for getting started with using the command line. But there’s a lot more you can learn about using a shell, and I’ll take you to the next level in this tutorial!


Getting Started

If you’re running Mac OS X, or your favourite flavour Linux, you’re all set. Just fire up the terminal, and keep going. If you’re on Windows, well, the default command set isn’t quite what a bash shell is. If you want some power, check out Microsoft PowerShell; however, the commands below won’t necessarily work there. You can get a bash shell on Windows, though:

  • Install Cygwim, a Linux-like environment for Windows.
  • Install msysgit; depending on the options you choose when installing, you’ll get a Git Bash that should work will all these commands.
  • Try Windows’ subsystem for Unix-based applications. Although I haven’t tried it myself, I understand you can get a Unix shell with it.

All right, let’s hop in!


1. Touch

touch

As a developer, one of your most common tasks is creating files. If you’re working from the command line, most of the time you’ll just pass the name of the file you want to create to your editor:

$ mate index.html
$ mvim default.css

However, occasionally you’ll just want to create one or more files, without editing it. In this case, you’ll use the touch command:

$ touch index.html
$ touch one.txt two.txt three.txt

It’s that easy. Actually, the touch command is for updating the access / modified date of a file; it’s just a nice side-effect that if the file doesn’t exist, it will create it.


2. Cat and Less

cat and less

Well, since it’s all about files, there’s a good change you’ll want to see the contents of a file from the terminal sooner or later. There’s a few commands that will do this for you. First is cat; cat is short for “concatenate”, and this command does more than output file contents; however, that’s what we’ll look at here. It’s as simple as passing the command a file:

$ cat shoppingList.txt

However, if the file is large, the contents will all scroll past you and you’ll be left at the bottom. Granted, you can scroll back up, but that’s lame. How about using less?

$ less shoppingList.txt

Less is a much better way to inspect large files on the command line. You’ll get a screen-full of text at a time, but no more. You can move a line up or a line down with the k and j respectively, and move a window up or down with b and f. You can search for a pattern by typing /pattern. When you’re done, hit q to exit the less viewer.


3. Curl

curl

Since you probably work with your fair share of frameworks libraries, you’ll often find yourself downloading these files as you work. Oh, I know: you can just download it from the web, navigate to the folder, uncompress it, and copy the pieces to your project, but doesn’t that sound like so much work? It’s much simpler to use the command line. To download files, you can use curl; proceed as follows:

$ curl -O http://www.domain.com/path/to/download.tar.gz

The -O flag tells curl to write the downloaded content to a file with the same name as the remote file. If you don’t supply this parameter, curl will probably just display the file in the commmand line (assuming it’s text).

Curl is a pretty extensive tool, so check out the man page (see below) if you think you’ll be using it a lot. Here’s a neat tip that uses the shell’s bracket expansion:

$ curl -0 http://www.domain.com/{one,two,three}.txt

Yeah, it’s that easy to download multiple files from one place at once. (Note that this isn’t curl functionality; it’s part of the shell, so you can use this notation in other commands; check this link out for more)


4. Tar and Gzip

tar and gzip

So, now you’re rocking command line downloads; however, there’s a really good chance that most of the things you download will be archived and gzipped, having an extension of .tar.gz (or, alternately, .tgz). So, what do you do with that? Let’s take a step back for a second and understand what exactly “archived and gzipped” means. You’re probably familiar with archives. You’ve seen .zip files; they’re one incarnation of archives. Basically, an archive is just a single file that wraps more than one file together. Often archives compress the files, so that the final file is smaller than the original ones together. However, you can still get a bit smaller by compressing the archive … and that’s where gzipping comes in. Gzipping is a form of compression.

So, back to that download. It’s been tarred (archived) and gzipped. You could unzip it and then un-tar it, but we’re all about fewer keystrokes here, right? Here’s what you’d do:

$ tar xvzf download.tar.gz

Wait, what? Here’s the breakdown: tar is the command we’re running; xvzf are the flags we’re using (usually, you’d have a dash in front, but that’s optional here). The flags are as follows:

  • x let’s tar know we’re extracting, not archiving.
  • v let’s tar know we want it to be verbose (give us some output about the action it’s performing).
  • z let’s tar know that the file we’re working with has been gzipped (so it unzips the file).
  • f let’s tar know we’re going to pass it the name of the archive file.

If you want to create one of these gzipped archives, it’s as simple as replacing the x flag with a c (to create an archive). The v and z flags are options: do you want output? how about gzipping? Of course, leave f; you’ll have to give the file name for the new archive (otherwise, it will all be output to the command line). After that, you’ll pass the command all the files you want to put in the archive:

$ tar cvzf archive.tar.gz index.html css js auth.php
$ tar cvzf archive.tar.gx *.txt

Just for completeness, I’ll mention that you can gzip archives (or other files) individually; when you do so, gzip replaces the original file with the gzipped version. To un-gzip, add the -d flag (think decompress.

$ gzip something.txt
$ gzip -d something.txt.gz

5. Chmod

chmod

Another thing you’ll do often as a web developer is change file permissions. There are three permissions you can set, and there are three classes that can receive those permissions. The permissions are read, write, and execute; the classes are user, group, and others. The user usually the owner of the file, the user that created the file. It’s possible to have groups of users, and the group class determines the permissions for the users in the group that can access the file. Predictably, the others class includes everyone else. Only the user (owner of the file) and the super user can change file permissions. Oh, and everything you’ve just read goes for directories as well.

So, how can we set these permissions? The command here chmod (change mode). There are two ways to do it. First, you can do it with octal notation; this is a bit cryptic, but once you figure it out, it’s faster. Basically, execute gets 1 ‘point’, write gets 2, and read gets 4. You can add these up to give multiple permissions: read+write = 6, read+write+execute = 7, etc. So for each class, you’ll get this number, and line them up to get a three digit number for User, Group, and Others. For example, 764 will give user all permissions, give group read and write ability, and give others permission to read. For a better explanation, check out the Wikipedia article.

If you have a hard time remembering the octal notation, you might find symbolic notation easier (although it takes a few more keystrokes). In this case, you’ll use the initial ‘u’, ‘g’, and ‘o’ for user, group, and others respectively (and ‘a’ for all classes). Then, you’ll use ‘r’, ‘w’, and ‘x’ for read, write, and execute. Finally, you’ll use the operators ’+’, ‘-‘, and ’=’ to add, subtract, and absolutely set permissions. Here’s how you’ll use these symbols: class, operator, permissions. For example, u+rwx adds all permissions to the user class; go-x removes executable permission from group and others; a=rw sets all classes to read and write only.

To use all this theory on the command line, you’ll start with the command (chmod), followed by the permissions, followed by the files or directories:

$ chmod 760 someScript.sh
$ chmod u=rwx g+r o-x dataFolder

6. Diff and Patch

diff and patch

If you’ve used version control like Git or Subversion, you know how helpful such a system is when you want to share a project with other developers, or just keep track of versions. But what if you want to send a friend some updates to a single file? Or what if another developer has emailed you the new version of a file that you’ve edited since you received the last copy? Sometimes, full-blown version control is too much, but you still need something small. Well, the command line has you covered. You’ll want to use the diff command. Before you make changes to a file, copy the file so you have the original. After you update, run diff; if you don’t send the output to a file, it will just be output to the command line, so include a > with the name for your patch file:

$ cp originalFile newFile
$ vim newFile #edit newFile
$ diff originalFile newFile
1c1
< This is a sentence.
---
> This is a short sentence.
$ diff originalFile newFile > changes.patch

As you can see, the diff is just a simple text file that uses a syntax the diff and patch command will understand. Patch? Well, that’s the command that goes hand in hand with diff. If you’ve received a patch file, you’ll update the original as follows:

patch originalFile2 changes.patch

And now you’re all updated.


7. Sudo

sudo

Sudo isn’t really a command like the others, but it’s one you’ll find a need for as you venture deeper into the command line world. Here’s the scenario: there are some things that regular users just shouldn’t be able to do on the command line; it’s not hard to do irrevocable damage. The only user who has the right to do anything he or she wants is the super user, or root user. However, it’s not really safe to be logged in as the super user, because of all that power. Instead, you can use the sudo (super user do) command to give you root permissions for a single command. You’ll be asked for you user account password, and when you’re provided that, the system will execute the command.

For example, installing a ruby gem requires super user permissions:

$ gem install heroku
ERROR:  While executing gem ... (Errno::EACCES)
    Permission denied - /Users/andrew/.gem/ruby/1.9.1/cache/heroku-1.9.13.gem
$ sudo gem install heroku
Password:
Successfully installed heroku-1.9.13

8. Man

man

Most of the commands you’ll use in a bash shell are pretty flexible, and have a lot of hidden talents. If you suspect a command might do what you want, or you just want to see some general instruction on using a command, it’s time to hit the manuals, or man pages, as they’re called. Just type man followed by the command you’re curious about.

$ man ln

You’ll notice that the man pages are opened in less.


9. Shutdown

shutdown

When you’re done for the day, you can even turn your computer off from the command line. The command in the spotlight is shutdown, and you’ll need to use sudo to execute it. You’ll have to give the command a flag or two; the most common ones are -h to halt the system (shut it down), -r to reboot, and -s to put it to sleep. Next, you’ll pass the time it should happen, either as now, +numberOfminutes, or yymmddhhmm. Finally, you can pass a message to be shown to users when the deed is about to be done. If I wanted to put my computer to sleep in half-an-hour, I’d run this:

$ sudo shutdown -s +30

10. History, !!, and !$

history

Since the command line is all about efficiency, it’s supposed to be easy to repeat commands. There are a few ways to do this. First, you can use the history command to get a numbered list of many of your recent commands. Then, to execute one of them, just type an exclamation mark and the history number.

$ history
...
563  chmod 777 one.txt
564  ls -l
565  ls
566  cat one.txt
...
$ !565

Granted, this is a terrible example, because I’m typing more characters to use the history than it would take to re-type the command. But once you’re combining commands to create long strings, this will be faster.

It’s even quicker to access the last command and last argument you used. For the latest command, use !!; the usual use case given for this is adding sudo to the front of a command. For the latest argument, use !$; with this, moving into a new folder is probably the common example. In both these cases, the shell will print out the full command so you can see what you’re really executing.

$ gem install datamapper
ERROR:  While executing gem ... (Errno::EACCES)
    Permission denied - /Users/andrew/.gem/ruby/1.9.1/cache/datamapper-1.0.0.gem
$ sudo !!
sudo gem install datamapper
Password:
Successfully installed datamapper-1.0.0

$ mkdir lib
$ cd !$
cd lib

Conclusion

If you’re as passionate about productivity as I am, the idea of using the command line as much as possible should resonate with you. What I’ve shown you here is just a sampling of the built in commands … then, there are many more than you can install yourself (look at something like the homebrew package manager, for example). But maybe you’re already proficient on the command line; if so, can you share another great command with the rest of us? Hit the comments!

May 07 2010

16:26

7 Simple and Useful Command-Line Tips

One of the most useful, but under-used, tools a web developer has is the command-line. The terminal often scares people away; so here’s where we demonstrate some of the most useful day-to-day commands.


1. The Basics

If you’re new to the command-line, you’re going to want to know a few things to help find your way around.

Changing directories

You can change to a different directory with the following:

cd ../relative/path/to/other/directory/or/file
cd /absolute/path/to/other/directory/or/file

If you get lost, you can go back to your “home” directory with the command “cd ~”.

Listing files and directories

If you need to know what files a particular directory contains:

ls ../relative/path/to/other/directory/or/file
ls /absolute/path/to/other/directory/or/file

You can use the “-l” switch to show the contents as a list, and the “-A” switch to also show hidden files (on Linux based machines, files and directories whose name begins with a “.” are considered ‘hidden’).

Showing your current directory

Sometimes you just want to know what directory you’re currently in!

pwd

This will display a path to your current folder.

Copying files

Copying files from one place to another is quick and easy:

cp /files/or/directories/to/copy /directory/to/copy/to/

You can also use the “-R” switch when copying to make it recursive, so all sub-directories and files are also copied.

But typing is slow, and what if I can’t remember the exact path or command?

Most of the time, the command-line has tab-completion enabled, so you can start typing the name of a command or a file path, press tab, and it will complete it for you. If there is more than one option, it won’t complete for you but if you double-press tab, it will list the options.

Tab-completion makes typing out long file paths much faster!

How do you know what options a command has?

There are a few ways to determine what options a command has. Most commands have a –help (or -help, or -h) operator available, which lists the possible arguments and options you can use:

cd --help

If you find that the brief help given by the –help operator isn’t enough, you can read more detail with the man program:

man mysqldump

Which will tell you all about the “nano” program. Simple commands like “cd” may not have an entry in man.


2. Making a Database Backup (with GZip Compression)

Backing up your database is something you should do often. Like most things, there are a lot of ways to do this, but using the command-line is one of the best. Why? Because it helps you get around potential problems like execution timeouts for tools like phpMyAdmin, and potential network dropouts from using a local administration tool like MySQL Workbench.

The command to run the backup is fairly small, but may require some explaining:

mysqldump -u mysqluser -p mysqldatabase

Now, to explain what’s going on here! The “mysqldump” program is a tool for creating database backups. The parameters being used are:

  • “-u” switch means you’re going to specify a username to connect with, which must follow, like “-u mysqluser” above
  • “-p” switch means you’re either going to immediately specify the password to use (with no space), or it’ll prompt you for one
  • The final parameter used in the example above is the name of the database to backup (of course!)

If you ran the command above, you would’ve seen the contents of your database go whizzing by on the screen. That’s good, because we know that part works (actually connecting to the database), but it’s also bad, because… where did it go? Answer: nowhere! It scrolled past, and that was it. Now we need to capture it and put it in a file.

To place the contents of the output into a file, for back-up purposes, we need to use what’s called a redirection.

mysqldump -u mysqluser -p mysqldatabase > db_backup.sql

So we added a redirecter, and the filename we wanted the output to go into. Now you should be able to see a file named “db_backup.sql”, and if you open it you can see a SQL script with the structure and content of your database ready for restoration or migration.

One last thing that could be useful for a backup, is compressing the SQL script. For this example, I’m going to use GZip compression, because it’s quite common, but you could also use Bzip2 or something else.

To add compression into this command, we just do what’s called piping. We pipe the output from the mysqldump through gzip, and then redirect it into the file we want, like so:

mysqldump -u mysqluser -p mysqldatabase | gzip > db_backup.sql.gz

I also added the “.gz” to the filename, so I know it’s compressed and not just plain text anymore (it’ll also be smaller!)


3. Restoring from a Database Backup (with GZip Compression)

So you’ve got a backup of your database (either using the method above, or some other way), and something has gone wrong and you need to restore, or you’re migrating it to a new server. You could use one of the other tools mentioned before, but in the example of phpMyAdmin, what if your database backup file is bigger than the allowed upload size? Well luckily, the command-line doesn’t mind.

The command to restore is very similar to the one for backing up. Firstly, without GZip compression:

cat db_backup.sql | mysql -u mysqluser -p mysqldatabase

We use the “cat” command to output the contents of the backup script, and pipe its contents into the mysql program. As you can see, the mysql program takes the same options as the mysqldump one does in section two.

Now if the script was GZip compressed, we can’t just output its contents into mysql, as it will be compressed data instead of a nice SQL script. So we do the following:

gunzip < db_backup.sql.gz | mysql -u mysqluser -p mysqldatabase

See, it's very familiar, just switched around a bit.

What's happening here is we run "gunzip" too and redirect the backup script into it to be decompressed. We then pipe the decompressed output into the "mysql" program.


4. Find / Replace in a Text File

Sometimes you have a big file, like maybe a database export, and you need to do some find / replace on it... but it won't open in any of your text editors, because your machine runs out of memory trying to open it! Well, here's a way around that, by using the command-line and a little regular expressions.

The way this works is to output the contents of the SQL script (or whatever file you're using), pipe it through a program called "sed," which is specifically form manipulating streaming content, and then redirect that output into the new file. Sound complicated? Well... I guess it is a little, but the command itself looks simple!

cat original_dump.sql | sed s/Japheth/Japh/ > new_dump.sql

The new part here is really the "sed" program. Basically what it's doing is taking input and matching the first pattern (in this case, my name, "Japheth"), and replacing it with the second pattern (in this case, a shortening of my name, "Japh"), then outputting that.


5. Securely Copying Files to / from a Server (over SSH with SCP)

If you're working on the command-line and need to copy a file, especially if you need to do it securely, why go and fire up your FTP client? Just use a program called Secure Copy, or SCP, which is especially for doing remote file copying securely. Secure Copy uses SSH to copy the files, so you need to make sure you can connect to the remote computer via SSH first (I'll talk about this a little more at the end of the article, so hold that thought).

The syntax of the scp command is similar to that of the cp command covered in section one, with the addition of the hostname of the remove computer and the username to connect with:

scp /path/to/local/file username@hostname:/path/to/copy/to/

The bits to note are "username@hostname:", which, as I explained above, are the username to use and hostname to use when connecting. You will be prompted to enter the password for that user, and you also will get a progress indicator for the copying so you can see how it goes.

You can use the "-r" switch (note: it's lowercase for scp, uppercase for cp) with secure copying to make it recursive. Also, if this is the first time using SCP or SSH to connect to the remote machine, you may be asked to accept an RSA fingerprint for security, which you should accept (assuming you're certain you're connecting to the correct server).

It's worth mentioning that this works both ways. You can also copy files from the remote computer to your local machine by switching the arguments around:

scp username@hostname:/path/to/remote/file /local/path/to/copy/to/

If you're SSHed into one web server, and you want to copy files to another one, you can use this command to copy the files directly without having to download them to your local computer first!


6. Finding Specific Files in a Large Project

Finding a file with a particular name

Want to find a specific file but not sure where in the many directories of your project it's hiding? (or even if there's more than one!)

find ./ -iname "index.php"

The "find" command is for locating files within a directory heirarchy. It has many options, so its uses are quite varied. Here I've specified to search in the current directory with "./", and used the "-iname" switch, which means to search for a file with a name like the one I supply. There is also a "-name" switch, but the "-iname" switch is case-insensitive, so it'll find INDEX.php as well.

Finding a file with particular content

Ever known that you had written a function for something, but can't remember which file it was in?

grep -iR myFunction ./

"grep" is a program for printing out lines that match a particular pattern. You can provide it with some switches, like the "-i" for making it case-insensitive, and "-R" for making it recursive in my example. Then provide a pattern, and the path to search in (here I'm searching the current directory with "./"). This example will show the filename and the line in that file for any matches it finds to "myfunction" (case-insensitve because of the "-i").

If your projects are Subversion working copies, you may find that it's annoying to see results from the ".svn" directories. To exclude particular directories from the search, use the "--exclude-dir=" switch, for example "--exclude-dir=.svn".


7. Performing Bulk Actions on Specific Files

Now we know how to find particular files; what if we want to do particular things with those files? For example, I often work on a Mac, and find that when I save files to Windows shares or Linux Samba shares on the network, Mac OS X kindly litters "._filename" files everywhere. So I like to be able to clean these up regularly.

To find such files, I use both methods from the previous section for finding files with a particular name:

find ./ | grep "\.\_.*"

We're finding a way to output all files in the current directory (recursively), and are then piping the output to grep, which ensures that it matches my regular expression. The regular expressions just says, "match anything that starts with a literal . followed by a literal _ followed by 0 or more of anything else." Run it like so to make sure you see the desired files.

Now to do something with all the files you captured from that command, you wrap it with back-quotes (``). If I wanted to delete all of them:

rm -f `find ./ | grep "\.\_.*"`

I have the "rm" command (to remove, or delete, files) with a "-f" switch (which means to force a delete without asking for confirmation), and it will run for each file returned by the command within the back-quotes!

I feel it would be irresponsible not to mention here that you should be very careful using the "rm" command. If you use the "rm" command with the "-f" switch, make sure you know exactly what you're going to be deleting, and that you really want it gone! If you use "-f", you won't get a second-chance.


How do I get Command-line Access to my Web Host?

I mentioned earlier in the article about connecting to a remote computer via SSH. A lot of these commands are most useful when used on your web server, which likely runs linux, so you'll need to be able to connect to the command line. The way to do so is by using a program called SSH, which does it securely.

On Mac OS X, or on linux, you can run SSH from the Terminal application:

ssh username@hostname

If you're on Windows, you'll need to use a freely available program called PuTTY.

You will be prompted for your password when you are connecting.

If you do not have SSH access to your web host already, you will most likely be able to request it, and they will set it up for you.


In Summary...

Like most things, "you don't know, what you don't know." It might seem difficult to discover how to use the command-line; but there's a huge amount of power available to you once you wrap your head around it! Hopefully, this article will get you started exploring! Any questions?


January 15 2010

23:18

Terminal, Git, and GitHub for the Rest of Us: Screencast

So you’ve read the tutorials, and still can’t manage to figure out this stuff? What is Git – and why do we even need it? If you fall into this category, much like I did at one point, I’ve recorded a video tutorial that hopes to teach you exactly how to get started. Rather than feeling your eyes blur over as you attempt to comprehend code snippets like “git push origin master,” relax, and let me explain it to you as best as I possibly can!

Video Exporting. Please watch video here.

Other Viewing Options

Further Reading

Write a Plus Tutorial

Did you know that you can earn up to $600 for writing a PLUS tutorial and/or screencast for us? We’re looking for in depth and well-written tutorials on HTML, CSS, PHP, and JavaScript. If you’re of the ability, please contact Jeffrey at nettuts@tutsplus.com.

Please note that actual compensation will be dependent upon the quality of the final tutorial and screencast.

Write a PLUS tutorial


Older posts are this way If this message doesn't go away, click anywhere on the page to continue loading posts.
Could not load more posts
Maybe Soup is currently being updated? I'll try again automatically in a few seconds...
Just a second, loading more posts...
You've reached the end.
(PRO)
No Soup for you

Don't be the product, buy the product!

close
YES, I want to SOUP ●UP for ...