Some lesser-known Bash tricks

Though alternatives like the zsh exist, the Bourne-again shell is still the de facto standard among all Unix shells. Maybe that's why some people refer to it as the Windows of the shells - although there are now better alternatives around, most users still stick with it. I am one of these users - that's why today's blog entry is about some useful, but little-known bash features. ;-) Note that you'll need at least Bash v4.0 for some of them. The Bash built-in shopt allows you to (de)activate various variables in order to control optional shell behavior. shopt called without an argument gives you an overview of all available options. To activate a feature, simply issue shopt -s OPTION - if you'd like to deactivate the feature again, a shopt -u OPTION suffices. If you wonder what's so tricky about this, just read on - basic knowledge of shopt is needed to benefit from the following. Everybody knows about the extremely useful for-loop, which allows it to perform the same command for all (or a subset of all) files in a directory. Its syntax is pretty much straightforward:

for file in *; do echo "Touching $file"; touch "$file"; done

This will touch every file in the current directory and tell you about it (not really a real world example, but you might get the point). However sometimes you'd like to also work on the files in all subdirectories - two popular solutions for this include the find command or recursion. As a rule, most users forget/don't know about the Bash's globstar option. If set (shopt -s globstar), you may use the following construct to also touch the files found in all subdirectories.

for file in **/*; do echo "Touching $file"; touch "$file"; done

Just want to touch all mp3 files? Here you go:

for file in **/*.mp3; do echo "Touching $file"; touch "$file"; done

Considering the previous example, you may notice that globbing doesn't include hidden files - which in most cases makes sense. Nevertheless, you can alter this standard behavior, by enabling the dotglob option using shopt While the above examples mostly cover batch processing, some options only influence the interactive shell usage. If cdspell is set, the bash will generously ignore spelling mistakes in the directory component of a cd command:

user@host /var/tmp $ mkdir example_
user@host /var/tmp $ cd example
-bash: cd: example: No such file or directory
user@host /var/tmp $ shopt -s cdspell
user@host /var/tmp $ cd example
example_
user@host /var/tmp/example_ $

autocd does a very similar job - if you issue a valid directory name without the prepended cd, you will automatically change to that directory. These are just some of the available options - man bash knows and explains them all, so start reading.... ;-)

Discontinuation of yaydl

If you're one of the few yaydl users out there, you might have noticed that I didn't put too much effort in the project recently. As I don't see any chance of maintaining yaydl in an appropriate way over the next months, I decided to discontinue the whole thing. Feel free to use the script as long as it works for you, but please don't email me any bug reports or the like. If you're looking for an alternative, I suggest you take a closer look at clive or youtube-dl.

Vim tips

Almost 4PM...time for some vim tips. :-)

  • autocmd Vim's powerful autocmd feature can be used to automatically perform certain commands when a specific event occurs. The events that can be used as triggers range from creating a new file to resizing vim's window. A complete list of available triggers can be obtained by typing :help autocmd-events in vim. So, how's this useful? Let's say you write most of your Perl scripts in vim, why should you insert the shebang and some other stuff manually in a new file, when the editor can do this for you? The following two steps show you how it's done:

    1. Create a new file ~/.vim/skeletons/skeleton.pl containing a shebang for Perl as well as the recommended use strict/warnings statements:

      p=$(which perl); mkdir -p ~/.vim/skeletons; cat << EOF > ~/.vim/skeletons/skeleton.pl
      #!$p
      use strict;
      use warnings;
      EOF
      
    2. Put the following in your ~/.vimrc

      autocmd BufNewFile *.pl 0r ~/.vim/skeletons/skeleton.pl | :normal G
      

    Now, when you're creating a new *.pl-file it is automatically prepended with the contents of ~/.vim/skeletons/skeleton.pl and vim starts at the end of the file. Needless to say, that you can use multiple autocmd commands to support languages other than Perl.

  • Syntax check Everyone knows about vim's :make command, but did you know that it's possible to set the make program for each file type separately?

    autocmd FileType perl set makeprg=perl\ -c\ %\ $*
    

    By adding this to your ~/.vimrc, :make will no longer invoke make file but perl -c file instead, when you're editing a Perl script. As usual, Perl is just an example - i.e. Ruby programmers might use ruby -c or the like.

  • Y? There's some inconsistency between deleting and yanking in vim: dd deletes the current line, D deletes from the cursor to the end of the line. yy yanks the current line, but Y also yanks the current line... To yank all characters from the cursor position to the end of the line, you either need to type y$, or add a custom mapping for Y to your ~/.vimrc:

    map Y y$
    
  • Matchit Typing % in normal mode finds the next item in the current line or under the cursor and jumps to its match. Items include c-style comments, parenthesis and some preprocessor statements. Unfortunately, there's no native support for HTML or Latex, but there's a handy little plugin, that adds support for these and many other languages: Matchit.

Enough for one day....

Bandwidth monitors

There are many tools available, that allow you to monitor (among other things) the current downstream of your internet connection. Some of them, like dstat and bwm-ng are handy console applications, whereas others integrate nicely into your desktop. Two popular examples for this would be conky or gkrellm. So, in general there's no real need for the following bash one-liner, unless you're just an ordinary user working on some poorly equipped linux box which doesn't offer any of the tools mentioned above. In that case, you'll be glad to have a dirty solution like the following available:

r=$(cat /sys/class/net/eth0/statistics/rx_bytes) ; while [ 1 ]; do n=$(cat /sys/class/net/eth0/statistics/rx_bytes); d=$(((n-r) / 1024 ));r=$n; echo "$d KB/s"; sleep 1;done

There is no need to mention,that eth0 must be replaced by your primary interface's name.

Remove Exif data

Sometimes it's advantageous to remove Exif metadata from image files, for example when posting images online. Fortunately, that's not a big deal since we're using linux:

mogrify -strip image.jpg

...or if you want to process more files:

mogrify -strip *.jpg

Linux, mplayer and the ZDF Mediathek

While the idea behind the ZDF Mediathek is not so bad at all, the actual implementation is a pain in the ass - especially the flash version of the website, which causes my Firefox to crash again and again... So I tried the HTML version of the site, which has two major advantages: 1.) Firefox doesn't crash anymore and 2.) one can watch the videos with any external program like vlc or mplayer. However, there's still a huge drawback: The videos are streamed via the Real-Time Streaming Protocol or the Microsoft Media Server Protocol, so basic operations like fast-forwarding, rewinding or pausing should be avoided. Additionally, as no (significant) buffering is performed, your internet connection will be in use for the whole runtime of a video, limiting other online activities. Looking for an easy solution for this, I checked mplayer's manpage and found the -dumpstream option. The rest was some elementary bash scripting:

mplayer -dumpfile "$(date +%y_%m_%d_%H_%M.dump)" -dumpstream "$(curl -s "$(curl -s "$LINK" | egrep "<li>DSL\s*2000\s*<a href=.*asx" | sed -r 's#.*href="([^"]+)".*#\1#')" | egrep -o 'mms://[^"]+')"

This will save any(?) video from the Mediathek to a local file called *current_date*.dump. If you didn't figure it out by yourself, $LINK must be set to / replaced by the actual URL pointing to your video (you'll need the URL to the HTML version, or do some additional preprocessing first). Before you ask: Of course I wrote an easy-to-use, ready-to-run script for this - it even does some limited error checking. It can be found here. Update: Seems like this only works for just a few videos, so don't be too disappointed if it fails...

yaydl 1.5.1

Version 1.5.1 comes with support for video.golem.de (ok....not as big as youtube, but who cares...) BTW: If you want to be informed about new versions without reading my blog (shame on you!), you might want to subscribe to yaydl on freshmeat.

Download the tar.gz