c u t u p @ c u t u p . o r g


[bash calendar oneliner] last modified: 05/04/2008 10:27 am

I made a nifty little one liner so cal will show you the current date. It even makes sure not sure not to mess up the formatting. I'm sure this is like, the millionth time this was invented, and I'm sure there's a better way to do it, and it's not even technically a one-liner, though it is short.

DATE=`date +%d`;REP=`echo $DATE | sed 's/./#/g'`;cal | sed "s/ $DATE / $REP /"

and you get something like:

    December 2005
 S  M Tu  W Th  F  S
             1  2  3
 4  5  6  7  8  9 10
11 12 ## 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31


UPDATE: already found a better one:

cal | sed "s/ $(date +%d) / $(date +%d | sed 's/./#/g') /"

UPDATE 2: it worked till the 17th, oops! Not all the dates have spaces on both sides. The best thing i could think of to do was just add spaces on each end of the lines, so now I'm using:

cal | sed "s/^/ /;s/$/ /;s/ $(date +%d) / $(date +%d | sed 's/./#/g') /"

UPDATE 3: thanks to someone at MacGeekery, I learned how to use shell escape codes. So here's a version that just bolds the current date:

cal | sed "s/^/ /;s/$/ /;s/ $(date +%d) /$(printf '\e[1m&\e[m')/"

UPDATE FOR NEW YEAR: you need to strip the leading zero from the date:

cal | sed "s/^/ /;s/$/ /;s/ $(date +%d | sed 's/^0//') /$(printf '\e[1m&\e[m')/"


cal | sed "s/^/ /;s/$/ /;s/ $(date +%e) /$(printf '\e[1m&\e[m')/"


cal | sed "s/^/ /;s/$/ /;s/ $(date +%e) / $(date +%e | sed 's/./#/g') /"


cal | sed "s/.*/ & /;s/ $(date +%e) / [] /"

[twitter bash curl] last modified: 03/28/2007 09:31 pm

I made a twitter client with bash and curl. It posts STDIN or arguments to twitter, or displays the you and friends timeline if theres no input. It uses .netrc for authentication.

# a twitter client (uses .netrc for auth)

[ "$1" == "-h" ] && {
 echo " use: $(basename $0) -h | [ tweet ]"
 echo "      -h help"
 echo "      no arguments gets latest updates"

function friends {
 curl --connect-timeout 5 -s -n $1 | awk '
  { sub(/^[^>]*>/,"",$0) }
  /text/ { 
  /relative/ { 
  /_name/ { 
   print $0 " : " m " [" at "]"

function update {
 curl -s -n -d "status=$msg" $1 &>/dev/null || echo "tweet broke"

if [ -t 0 ]; then msg="$*"; else msg="$(cat -)"; fi

if [ "$msg" ];then
 update http://twitter.com/statuses/update.xml
 friends http://twitter.com/statuses/friends_timeline.xml

[ssh scp bash location] last modified: 03/25/2007 02:06 pm

Making ssh/scp aware of location on laptops.

~/.ssh/config is nice - I have a bunch of hosts and options aliased there. The problem is that depending on which network I'm on I might need to connect to a given host externally with one configuration, or internally. It would be nice to have the computer figure out which configuration it should use instead of making me do the work.

I futzed around with scripting a wrapper for ssh/scp that would be smart about how it connected based on my wlan location, but finally figured out a way to do it transparently - without using other commands, having multiple aliases for the same machine, or changing usage in any way.

First, for each network I want custom settings for, I make a copy of ~/.ssh/config as ~/.ssh/<name of network> and edit the entries for the machines that are different on that network.

Next, I have a shell script that figures out where I am, and if there is a config file for that network in ~.ssh/. If there is, it spits out the name of the network/filename, else it simply prints "config". I called that script lan. The script looks something like this on my mac with airport:

/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I | awk '
 / SSID/{for( i=2;i<=NF;i++ )ssid=ssid $i " ";sub(/ *$/,"",ssid)}
 END{if( ssid ){print ssid} else {print "config"}}

On Linux, something like this should work:

/sbin/iwconfig | awk '
 /ESSID/{if( $NF ~ /ESSID:/ ){split($NF,a,"\"");if( a[2] )ssid=a[2]}}
 END{if( ssid ){print ssid} else {print "config"}}

Finally, I have a couple of functions in my .bashrc, that look like this:

function ssh {
 /usr/bin/ssh -F ~/.ssh/"$(lan)" $*

function scp {
 /usr/bin/scp -F ~/.ssh/"$(lan)" $*

The full path to the ssh/scp executable is necessary so the functions don't just call themselves over and over again, and $(lan) returns the output of the lan script. Now, ssh/scp will transparently use the correct config file for all commands.

The nice thing is you can tweak the lan script for ethernet connections or whatever, because all it has to do is spit out a filename, and you can insert other functionality into the base commands. For example, I have mine set up so that calling ssh -ls will return a nicely formatted list of my defined hosts and aliases.

[bash roulette] last modified: 03/25/2007 02:06 pm

spotted this somewhere and it's priceless. Russian roulette in bash:

sudo [ $[ $RANDOM % 6 ] == 0 ] && rm -rf / || echo "You live"

[bash airport wlan homepage] last modified: 03/25/2007 02:06 pm

If you have an Apple laptop with Airport this bash line returns the SSID of the current network:

/System/Library/PrivateFrameworks/Apple80211.framework/Versions/A/Resources/airport -I | awk '/ SSID/ {printf $2}'

With that in mind i made a smart homepage script in php. I run it on my local webserver and use it as my homepage.

Given a list of trusted SSID's it will test internet connection and:

  1. if connected to a trusted network it will load homepage if connected or display an error if not connected
  2. if connected to another network it will display SSID and connection status
  3. if not connected to a wireless network, show homepage if internet detected (like ethernet or whatever) else display an offline page

There's other ways I could imagine running this, but it should be pretty easy to modify for diferent behavior.

[geektool bash] last modified: 03/25/2007 02:03 pm

So there's a Tiger compatible version of GeekTool floating around finally, and I've been playing around with it the past couple days.

I'm still a beginner at shell scripting and the whole gestalt of modern computing, and I've found this not only fun to play with, but also quite educational, especially with regards to those geekiest of tools, bash one-liners.

I've learned a lot from this, for instance that I like awk. It certainly isn't awkward, lol. And take away my propensity for just doing cool crap because I can, and this thing can still be really quite actually real-world useful. It's already replaced half my Dashboard - I find the displayed information simultaneously more noticible and less in the way.

So here's where I'll put my setup, and any other stuff I found that works nice with GeekTool even if it might not maybe be all that actually useful all the time. And of course, links to the work of others.

My Dealy:

Here's what I got on my desktop right now:

I also have separate group that displays the latest satellite weather maps. Sweet.


Geektool can display pictures from a url. So the trick is to find .jpgs online that are refreshed every so often and where the name of the file does not change. I found a bunch at weather.com and some more at uswx.com. Right now I have a group, separate from all the other stuff, that has three pictures running:

//us visible satellite
// northeast infrared satellite
// world satellite

There's still room for more, but for now this replaces my US Weather dashboard widget nicely. Notice that you call tell from the picture urls that the filename is not likely to change. If there's a date or time in the name of the picture, this wouldn't be so easy.


By default, Geek Tool windows are black text. My backgrounds are usually dark, so I have to change the text color to white before I can even see anything there. I wouldn't mention it except that I couldn't figure out whether my command wasn't working or the display was wierd when I got started.


I picked this up somewhere, it seems to show all the connections on your network

netstat -ab -f inet | grep -i established | sort +4

This one's neat. It shows the IP's of everyone that visited your site:

tail -5000 /var/log/httpd/access_log | grep -v | awk '{print $1}' | uniq

Or even:

tail -5000 /var/log/httpd/access_log | grep -v | awk '{print $1}' | uniq | nslookup -silent | awk '/name = /'

which gives you their hostname. I'm not clear on how to translate this information into a more useful domain name, when I do I imagine I will probably end up using this a lot.


macoshints search for "geek tool"

[bash tricks] last modified: 03/25/2007 02:01 pm

some nice bash stuff:

for .inputrc, this one makes up and down scroll through history matching whatever is already entered. If nothing is entered up and down work normally, but if, say vi is entered, it will be like vi ^R. Very nice:

# "\e[A" and "\e[B" being whatever your terminal uses for up & down.
"\e[A": history-search-backward
"\e[B": history-search-forward

for .bashrc, a function that cd's to a directory and lists the contents it takes ls arguments and a directory. for example, cl goes to home dir and lists contents. cl -l goes to ~/ and long lists contents. and cl -lrt public_html shows the contents of public_html in long list reverse time order.

function cl () {
 case $1 in
  -*) local o=$1; shift;; 
 cd $* && ls $o

[bash ssh bashrc] last modified: 03/25/2007 02:01 pm

If you have a server at home or on a wireless network you frequent, you'd connect to it with an internal IP. But off the LAN, you connect with its domain name or external IP. Here's a simple and obvious function for your .bashrc that figures out where you are and connects accordingly. If defaults to your username but allows you to specify another.

Pick the function for your OS, substitute the stuff in brackets, add a port if you need to, and you'll probably rename the function to something better than sssh, like the server name or something.

# smart ssh for linux
function sssh() {
 WLAN=$(/sbin/iwconfig 2>/dev/null | awk '/ESSID/{split($4,a,"\"");print a[2]}')
 [ $1 ] && local AT='@'
 [ "$WLAN" == "<wireless_ssid>" ] && ssh $1$AT$<internal_ip> || ssh $1$AT<domain_name>

# smart ssh for mac
function sssh() {
 WLAN=$(/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I | awk '/ SSID/ {print $2}')
 [ $1 ] && local AT='@'
 [ "$WLAN" == "<wireless_ssid>" ] && ssh $1$AT<internal_ip> || ssh $1$AT<domain_name>

Then you connect with sssh [username] wherever you are and it figures itself out.

Yeah, it's obvious but it's not like I can claim I thunk of it on my own.

[bash screencast] last modified: 03/25/2007 02:01 pm

Just for kicks I made a little script that takes a screenshot of my desktop, shrinks it, and uploads it to my server. I set it to run every minute with cron, and added some code that keeps it from updating if my screensaver is running.

Here's the code. It's pretty mac specific, using the screencapture and sips commands: #!/bin/bash

test=`ps -c -U $(whoami) | awk '/ScreenSaver/'`

if [ "$test" ]
 /usr/sbin/screencapture -C temp_screen_cap.jpg
 sips --resampleWidth 300 --setProperty format jpeg --setProperty formatOptions low temp_screen_cap.jpg --out temp_screen_cap.jpg
 scp "temp_screen_cap.jpg" user@server.com:path/to/screen.jpg
 rm temp_screen_cap.jpg

You need to modify the upload path and you can change the width, and this required generating a PGP pair for the local and remote machines as described here, otherwise you'd need to enter a password every time scp runs.

The entry in crontab looks like this (replace [TAB] with real tabs):

*/1[TAB]*[TAB]*[TAB]*[TAB]*[TAB]/Full/path/to/script > /dev/null 2>&1

For "porn mode" just comment out the line with a "#"

I dunno, I like it :)

UPDATE: Here's a more fleshed out script I use.

[bash fink completion] last modified: 03/25/2007 02:01 pm

A recent hint at macoshints shows how to create a shell script that will make all the Applications on your system available with tab completion. I've gotten used to Quicksilver and was interested in how this replicates some of that idea in the shell. I started poking around and ended up doing this another way.

Apparently, programmable completion has been around in bash for a while, but it's not really scripted by default. However, there are scripts and packages floating around to demonstrate it's capabilities. I like fink, and sure enough, fink has a bash-completion package. Here's what I had to do to get it working: Installed the bash-completion package from fink:

fink install bash-completion

Added the following lines to my .bashrc file:

source /sw/etc/bash_completion 
bind '"\t":menu-complete'

The first line calls the bash-completion script that fink installed (make sure you source it after any lines that affect PATH's), and the second line enable single-tab completions. This makes a Tab display the first possible completion, another Tab display the next, and so on, instead of the default double-tab-ask-first list.

Once this is turned on, it not only completes commands, but it can complete gui apps

open -a (TAB)

including ones it finds in Developer (it found xcode), complete ssh and scp (from known hosts), like

ssh [username@](TAB)

and man pages the same way, and etc ...

I wish there was a man file to enumerate more of what it does, but I learned that this all leverages the shell builtin complete. And looking in the /sw/etc/bash_completion file, we can see which of those it uses, and how. Neat stuff like directory commands only see directories, user commands only see users, network interface completion, man completion ... theres A LOT in there!

Theres also a /sw/etc/bash_completion.d/ folder that contains some more scripts, most of them seem to be custom for mac, like open.sh and fink.sh. I looked at the open script and right at the top is the search path. It was trivially easy to add extra places for it to look for apps. I added my games folder where I keep some apps separate. Seems easy enough to add more scripts too.

It's crazy, my Terminal just got a whole lot smarter, and it will take me a while to catch up. Unix heads always had all this stuff ages ago, but sometimes I guess they forget to let us know.

UPDATE: Debian seems to include the bash completion scripts in its base install, all you have to do is uncomment a couple of lines in the default .bashrc to get it running. And it's available as a package in cygwin as well.

[All Posts] [top]