Pages

Showing posts with label bash. Show all posts
Showing posts with label bash. Show all posts

Wednesday, August 17, 2011

Tab completes my life

Sorry for the somewhat awkward title. I just couldn't resist the geeky pun, and couldn't come up with a better phrase to express it. Hope you got the short message from the title. Also please forgive the awful (or awesome?) prose below. I've always wanted to write a post like this :)

Having been a happy Linux user for the past year-and-a-half, I respect the art of command line-fu. The most useful, yet simple, trick in the bag of the CLI ninja is, of course, the all-powerful Tab key. In one stroke - literally - it can help him type even the longest of commands with minimal key presses. I just love going ..<Tab>..<Tab>..<Tab><Enter> on my terminal, commands flowing at the speed of thought.

Now I'm so used to it, I expect it to be present everywhere - my browser, my text editor, in git commands, in the python interactive interpreter. Basically, I expect my computer to do its job - that is, helping me out while I try to do mine. That does not happen easily, however. So I set out on a quest - to try to have some form of Tab-completion in as many programs as possible. Below, I chronicle my journey, for the benefit of the traveller seeking the same end :-

The Switch from Bash to Zsh:
All Linuxes come with the same default shell: bash. However, there's another shell out there - zsh - which is little known, but extremely powerful. It's the first step from CLI apprentice to CLI productivity master. There are some excellent plugins available for zsh which add tab completion for many commands like git, pip, gem, and kill along with some bonuses. It'll also help you out with many other small things, like ignoring case and correcting spelling mistakes.

If you're thinking to try out zsh, I'd recommend installing Oh My Zsh! first thing after you install zsh itself. It'll make it much easier to set up zsh to your liking, replete with themes, plugins, and aliases. Also, as it turns out, the $RPS1 environment variable, along with the git support in Oh My Zsh!, pretty much renders my alternative (and very useful) bash prompt obsolete.

The Text Editor:
Since I'm a die-hard Emacs user, this section's a bit biased. For Emacs, I use Auto Complete Mode. It's fairly easy to setup, and blazing fast once you get used to it. Note that this is not code completion, it's simple, cross-buffer word completion, so it'll suggest words based on what's in the rest of the buffer, or in other open buffers. I find this better than code completion for the simple reason that code completion would require me to install separate plugins for each language I use, while on the other hand, word completion is universally effective, if not as accurate. Heck, it even works in comments. Combine that with YASnippet, and you'll find yourself with one finger on the Tab key nearly perpetually, and code flowing from your fingers.

Oh, and let's not forget ido-mode. It's the coolest, dead-simplest Emacs plugin ever.

For Vim users who feel left out, a quick Google search yields this.

The Interactive Interpreters (Python and Ruby):
I hated it when I fired up python the first time and it didn't offer Tab-completion. I later understood that since whitespace is significant in Python, completion is not enabled by default in the interpreter (or the Python REPL, in purist-speak). I figured spaces could be used for indentation just as easily as tabs, so I enabled completion using this .pythonrc. It's not like I miss tabs for indentation now.

Coming to irb (the Ruby interpreter), you can have Tab-completion and syntax highlighting in it using the wirble gem and a .irbrc. Pretty straight forward, supremely effective, no down-sides.

The Browser:
Not much to say here. Probably the only thing you can Tab-complete in a browser is URLs, which the latest versions of Firefox and Chrome already do, anyway (it's not true, CLI-style tab-completion; just passable). If you want word completion too and you're on a recent version of Firefox, use this addon. Or, if you're using an older Firefox version, you could try this one.


Here ended my quest. Let your chronicles and criticisms be outlined in the comments below.

Thursday, July 28, 2011

The alternative (and very useful) bash prompt

Almost all Linux users have used bash at some point, but how many of them know how to customize it to their liking? Here is a screenshot of one custom bash prompt I've created, which I find much better than the default (it took me a few hours to reach this point, owing mainly to my poor skills in bash scripting):

Click the image to view it properly.
So, other than showing useful stuff related to git repositories, it gives me a full line to type my command, and separates each command with a hyphenated separator and a newline, so I can see it clearly as I scroll upwards. The corresponding code snippet is (put it at the end of your ~/.bashrc if you wish to use it):

PS1='\[\033[01;34m\]\$\[\033[00m\] '

parse_git_dirty () {
    [[ $(__git_ps1) != "" ]] && [[ $(git status 2> /dev/null | tail -n1) != "nothing to commit (working directory clean)" ]] && echo "*"
}

print_pre_prompt () {
    # the first part of the prompt, i.e., the user's name
    local PS1U=$USER

    # the second part of the prompt, i.e., the present working directory
    local PS1WD="${PWD}"
    if [[ $PS1WD = "$HOME" ]]; then PS1WD=\~; fi
    if [[ $PS1WD = *"$HOME"/* ]]; then PS1WD=\~${PS1WD#$HOME}; fi

    # the fourth and last part of the prompt, i.e., the git stuff
    local git_dirty=$(parse_git_dirty)
    local git_dirty_color="\033[1;31m"
    local git_clean_color="\033[1;30m"
    if [[ $git_dirty = "*" ]]; then local git_color=$git_dirty_color; else local git_color=$git_clean_color; fi
    local PS1R=`__git_ps1 "%s"`$git_dirty

    # the third part of the prompt, i.e., the separator consisting of hyphens
    local PS1SEP=""
    while [ $(echo ${#PS1U}+${#PS1SEP}+${#PS1WD}+${#PS1R}+3 | bc) -lt $COLUMNS ]; do
        PS1SEP=$PS1SEP-
    done

    # putting it all together
    printf "\n\033[1;32m%s \033[1;34m%s \033[0;36m%s $git_color%s" "$PS1U" "$PS1WD" "$PS1SEP" "$PS1R"
}

PROMPT_COMMAND=print_pre_prompt

Rather than explaining the code (which I'm not very clear about myself), I'll point you to some links which helped me along the way:
1. https://wiki.archlinux.org/index.php/Color_Bash_Prompt
2. http://superuser.com/questions/187455/right-align-part-of-prompt
3. https://gist.github.com/306785/4da3e39fc012475140fdf33ef0f6bc0a6e7c04a5

-----
Liked this article? How about following me or Rajat on Twitter?

Tuesday, June 7, 2011

Base conversion in BASH

As programmers, we often encounter numbers written in binary or hexadecimal format. Mostly it is written as the context is made easier. For example, a set of flags is better represented as binary than integer. Here's an example :-
#define IS_TRUE        0b01     // same as 1
#define IS_FALSE       0b00     // same as 0
#define CONFIRM        0b10     // same as 2
#define DOUBTFUL       0b00     // same as 0
This example might not be very common, but this demonstrates the use of binary representation. These flags are useful at binary level to facilitate " bit-level AND " and various other operations.

In such scenarios, it could get confusing as to what the number represents in integers. Many, here, would suggest creating a program in the language of your choice and using it for base conversion. So, here I explain how one can use BASH itself.

BASH allows base conversion very easily. Fire up a terminal and try this :-
echo $((2#1010101))
I assume, I needn't explain $((<operation>)) is necessary for mathematical operations in BASH.  The output of the above command is 85, which is the decimal value of the number  "0b1010101".

So here we have a simple base converter. Interestingly, the base conversion allows to convert from any base to decimal this easily  :

<base>#<number_in_base>

The above is sufficient to convert number given in any base to decimal value. Go ahead, try it out.

Friday, March 4, 2011

Bash script for Extracting text

This is a script that I made today to solve a particular problem, but I do realise that many a times I, or anyone for that matter, would need to use something similar. For the same reason, I decided I'd share the script here.

The script was made (as my IITG friends would understand) to extract a set of e-mail addresses from a text file that contained a lot more data. Basically, the file contained the information of each student (Roll no, name, email) in a single line with 'space' as the delimiter. Using this (space as delimiter) characteristic, I extracted the necessary information and dumped it in a file.

while read line
do
line=${line##* }
echo $line
done

This script was sufficient to extract the necessary information. The next task was to dump the output into another file. (if the above was saved as script.sh)

$ cat list| bash script.sh > list

This should have been sufficient, but in my case, I had to pass the 'list' file once again through the script.sh file to generate the desired result.

Consequently, to create a list with commas, the following thing could be performed.


while read line
do string=$string,$line
done
string=${string#,*}
echo $string

This takes care of concatenating the strings with a comma in between consecutive elements.

The above set of commands helped me create a list of over 580 e-mail addresses in less than 10 minutes (including the time taken to create the scripts), way faster than the manual method of 'copy-paste'. Note that I call it a manual method.

I hope this tutorial sheds some light on the use and power of simple bash scripts to solve everyday problems and save a lot of time. Do revert in case of any doubts or confusions through comments.

exit(0)    // End of post