Ten Tweetable Scripts
Yesterday morning I proposed a contest to create the best one-line program that would fit inside Twitter’s 140-character buffer. To kick things off, I wrote this 105-character script which displays a small animation:
s="-<";while true;do echo -ne "$s\r";s=`sed 's/->$/-<-/;s/^/;s/-<-/;s/>-/->/;'<<<$s`;sleep 0.1;done
Arturo (or Pupi as his friends call him) wrote a 135-character morse code decoder in shell:
m=etianmsurwdkgohvf?l?pjbxcyzq;p=0;while read -sn1 c;do [ -z "$c" ]&&p=0&&echo&&continue;let p+=c;echo -ne \\b${m:$p:1};let p+=p+2;done
Press ’0′ for dot, ’1′ for dash, and hit space (or enter) as a char separator. Wow!
I learned a few tricks from Arturo’s script. First, he uses the ${} braces operator to take substrings, like so:
${var:offset:length}
This is incredibly useful! You can actually do shell arithmetic in the offset and length parameters, too. So for example,
${var:i+1:a-3}
is valid for shell variables $i and $a. And to find the length of a string, you can use:
${#str}
So str=”foobar”; echo ${#str} will print “6″. You can read more about the braces operator in the bash info page.
Another thing I learned from Arturo’s script is the versatility of the ‘read’ builtin in bash. Pupi uses the -s argument, which causes read not to echo its input (useful for inputting passwords) and -n1 which tells it to only read one character. Also, Arturo uses [ test ] && operation, which is a handy short-hand for an if statement in shell (and other languages).
Pãdraig Brady wrote this excellent screensaver:
tr -c "[:digit:]" " " < /dev/urandom | dd cbs=$COLUMNS conv=lcase,unblock | GREP_COLOR="1;32" grep --color "[^ ]"
Pãdraig makes use of the square-brace character class operator in tr(1) to filter out all the numerals, which bash also supports.
Building on what I learned from Pupi, here is one I wrote that I call paint.sh:
c=12322123;x=20;y=20;while read -sn1 p;do k=${c:(p-1)*2:2};let x+=$((k/10-2));let y+=$((k%10-2));echo -en \\033[$y\;"$x"HX;done
Use the 1 2 3 and 4 keys to move the cursor around the screen. It's an etch-a-sketch for your terminal!
You can see that I made use of the read -sn1 trick from pupi as well as the braces operator to substring. I also used ANSI escape codes to position the cursor.
And this is one I call rockband.sh:
while read -sn1 p;do s="";for((i=0;i<$p;i++));do s=x$s;done; yes $s > /dev/audio&sleep 0.1;kill %%;done
Use the number keys to play different tones. When you're done, hit Control-c.
The way it works is that the ASCII value of each character you send to /dev/audio specifies the excursion of the speaker diaphragm (roughly). The 'yes' command prints whatever string you give it, followed by a newline character (ASCII 13, pretty low), over and over again. So the longer the string of 'x' characters you pass to 'yes', and which 'yes' prints between newlines, the slower the oscillation of the speaker diaphragm, and the lower the tone. Neat, huh? I learned this trick from my boyhood friend Edward Loper many years ago.
And here's the last one I wrote:
s=" #55755071317011117011117075557";for i in `seq 2 $((${#s}-1))`; do k=${s:i:1}; for b in 1 2 4; do echo -n "${s:(k&b)/b:1}"; done; echo; done
Miguel submitted this tiny function plotter:
for x in `seq -1 .05 1`; do y=`echo "s($x*8)*10+10" | bc -l`; for p in `seq 0 $y`; do echo -n " "; done; echo "*" ;done
And here's another plot:
for x in `seq -5 .5 5`; do y=`echo "$x*$x" | bc`; for p in `seq 0 $y`; do echo -n " "; done; echo "*" ;done
Those last three scripts make use of the venerable "seq" command to generate a series of numbers. Miguel uses fractional steps, but if you only need integers you can also use braces in shell, like this:
sum=0;for i in {1..100}; do let sum+=i; done; echo $sum
Ryan Paul of ArsTechnica fame wrote this Ruby script:
proc{|f|f[proc{|x|x+1},0]}[proc{|x,y|proc{|f,z|x[proc{|w|y[f,w]},z]}} [proc{|f,x|f[f[f[f[f[f[f[x]]]]]]]},proc{|f,x|f[f[f[f[f[f[x]]]]]]}]]
Ryan is using the “proc” primitive in Ruby, which allows you to create an anonymous function (like lambda in lisp), and which I didn’t know about even though I’ve been coding Ruby off and on the last few months. He uses Church encoding to encode the numbers 7 and 6, and lambda calculus to multiply them, thus confirming that he is the most awesome IT journalist working today.
Finally, Jay Wren sent in this C program:
main(x,y){for(;x++;) for(y=2;x%y;)printf( ++y/x+"\0%d\n",x);}
of which he is not the original author (and which I suspect was an IOCCC entry), but which is a very compact way of generating all the prime numbers. The author uses the args to main to save space on variable declaration, and the leading null-terminator in the string is a really clever way to select whether or not to print the output without an if statement. Lots of cleverness in there (though the algorithm to find primes is just brute force).
There were too many good entries to declare a winner, and maybe a contest was the wrong idea anyway. But this was a lot of fun. If you want to send me a script on twitter, be sure to send a “@natfriedman” message after, so that I notice you.
Thanks to Fahim Zahid for help creating the mini screencasts.
Update: Be sure to read More Tweetable Scripts for more goodies!
Jakub Steiner on 11 April 2008 at 10:59 am
artform.
Trackback from meneame.net on 11 April 2008 at 6:20 pm
Jason Brownlee on 12 April 2008 at 1:01 am
Amazing!
Reminds me of the 6 word stories printed in Wired in 2006 titled: Very Short Stories.
Steve Krenzel on 12 April 2008 at 1:18 pm
Awesome post Nat.
Jason,
Funny you linked to that wired article, I had read it a while ago and thought it’d be cool to have a site for people to write their own six word stories, comment on others, rate them, etc… so I wrote SixIsEnough. Check it out, it just went live a week or two ago.
root on 12 April 2008 at 4:22 pm
> tr -c “[:digit:]” ” ” … grep –color “[^ ]”
>
> Pádraig makes use of the square-brace character class operator in bash to filter out all the numerals.
The [:digit:] syntax is part of tr, not part of bash. Look at the tr manpage for more details, like [:upper:] and [:lower:].
Earle Martin on 12 April 2008 at 4:55 pm
Many Perl quines fit nicely: http://www.nyx.net/~gthompso/self_perl.txt
Ralph Corderoy on 13 April 2008 at 8:09 am
> Pádraig makes use of the square-brace character class operator in bash to filter out all the numerals.
No, he’s using a character class in tr(1) to do that; bash isn’t involved. And I’m unclear why he has `lcase’ as one of dd(1)’s conversions when nothing but digits will be read by dd(1). It’s redundant.
Pingback from Twittable scripts « Codeflicker on 13 April 2008 at 9:48 am
Pingback from Tony’s Research Blog » Blog Archive » Ten Tweetable Scripts on 13 April 2008 at 11:00 am
Pingback from Turulcsirip - macat on 13 April 2008 at 10:38 pm
Phill MV on 14 April 2008 at 1:11 am
That was last C program is ridiculous awesome.
nat on 14 April 2008 at 7:11 am
@root, @Ralph – Whoops, good point! Thanks, I fixed that in the text.
@Jason, @Steve – The 6-word Hemingway story still haunts me.
Justin on 15 April 2008 at 10:05 am
I don’t use twitter, but this would fit:
s=.o0O0o.o0O0o.o0O0o.o0O0o.o0O0o.o0O0o.o0;n(){ for x in `seq $1 $2 $3`;do notify-send ${s:0:x}; done };while :;do n 1 2 39;n 39 -2 1;done
it could be made to be more obfuscated I suppose, but I already had it lying around, I just removed the newlines
nat on 15 April 2008 at 2:34 pm
Woah, @Justin – nice one!
Ryan Paul on 16 April 2008 at 12:50 pm
Thanks.
Arturo Espinosa on 16 April 2008 at 4:05 pm
Hey, Nat.
Here goes a new one, plenty of color… 139 chars, rainbow.sh
a=1;for i in {1..34};do printf %$[40-${#a}]s”$(eval $(echo $a*$a|bc|sed ‘s/$/0/;s/\([0-9]\)/tput setab \1; echo -n \\ ;/g’))”\\n;a=1$a;done
Chan on 19 April 2008 at 1:02 am
I really enjoyed reading this article!
Nice blog!!!
Pingback from links for 2008-04-20 | fudge.org on 20 April 2008 at 3:35 pm
Antonio Ognio on 1 May 2008 at 1:21 pm
This is another nice short script I adapted from here http://www.shell-fu.org/lister.php?id=161
echo “Randomly-generated password: `
Pingback from Tiny Website Contest | AF-Design on 23 May 2008 at 4:47 pm
Binny V A on 26 May 2008 at 11:55 pm
For a change, here is something useful. A less than 140 char script to post a tweet to twitter…
curl –basic –user “[User]:[Password]” –data-ascii “status=`echo $@|tr ‘ ‘ ‘+’`” “http://twitter.com/statuses/update.json”
Pingback from Bronikowski.com » Blog Archive » MaÅ‚e jest użyteczne (choć niezbyt piÄ™kne) on 8 December 2008 at 7:54 am
Pingback from Tony Thompson » Blog Archive » On Brevity. on 7 February 2009 at 1:34 pm
Lars Holm on 12 February 2009 at 9:10 am
To root (6) about using [:digit] – I thought it was a part of regexpr, and that I could use it in bash, grep, gres not only in tr. Instead of writing–> while true; do I thought You could write–> : [expr]. Perhaps I’m mixing bash, ksh, zsh and tcsh together.
Woedoggy on 17 July 2009 at 9:04 pm
The initial script that kicked all this off: Could someone explain the use of “<<<”
Nat Friedman on 17 July 2009 at 11:53 pm
Ah, good question. That’s a cool feature of the shell.
When you run a command like cmd < << str, then str is shell-expanded and fed to cmd as standard input.
For example:
$ bc < << "7+3"
10
Thanks for asking!
Pingback from more comments on Apple, and other stuff « whileloop on 4 August 2009 at 7:40 am
Maniac Programmer on 10 August 2009 at 10:07 pm
while 1 do done;Priit Laes on 15 August 2009 at 12:08 pm
Seems that something in your blog software has broken all the ampersands and comparison characters by double escaping them :S
Nat Friedman on 15 August 2009 at 1:56 pm
Fixed, thanks for pointing this out. WordPress does this from time to time – it feels like using Frontpage sometimes.
Renee on 21 August 2009 at 3:08 am
Can anyone tell me why ‘b’ is the same note as ’4′ while all the other alphabet keys are the same notes as ’0′ and ’1′?
Pingback from tys lefering (twlevo) 's status on Saturday, 10-Oct-09 20:20:43 UTC - Identi.ca on 11 October 2009 at 1:20 am
Joe Ryan on 8 January 2010 at 6:19 pm
I continue to get an error when running the first script. I am still a Linux/Shell newb so it may be me missing something obvious. Here is the error I get.
sed: -e expression #1, char 19: unknown option to `s’
buy diflucan without no prescription veterinary on 3 July 2010 at 11:08 pm
I bookmarked this guestbook., Real buy diflucan without no prescription veterinary, [url= http://www.wearediabetic.org/buydiflucanwithouts/bio ]Real buy diflucan without no prescription veterinary[/url], 228681,
Pingback from LXer: Ten Tweetable Scripts | Coders & Admins on 9 September 2011 at 9:51 pm
Lakia Christie on 25 October 2011 at 10:18 pm
Magnificent beat ! I wish to apprentice while you amend your web site, how could I subscribe for a blog web site? The account helped me a acceptable deal. I had been tiny bit acquainted of this your broadcast provided bright clear concept
Marguerite Balding on 5 December 2011 at 2:28 am
Great work! This is the kind of information that should be shared around the internet. Shame on Google for not positioning this publish higher! Come on over and discuss with my web site . Thanks =)
titanium wedding rings for women on 7 February 2012 at 12:41 pm
Excellent blog here! Also your website loads up fast! What host are you utilizing? Can I get your affiliate link to your host? I wish my website loaded up as quickly as yours lol
Charlie Arquette on 21 February 2012 at 4:06 am
I’m impressed, I have to say. Really hardly ever do I encounter a blog that’s each educative and entertaining, and let me inform you, you’ve got hit the nail on the head. Your idea is outstanding; the difficulty is something that not enough persons are talking intelligently about. I’m very completely happy that I stumbled across this in my search for one thing regarding this.
Maida Tilton on 23 March 2012 at 2:02 pm
What’s up, after reading this remarkable piece of writing i am too happy to share my familiarity here with friends.Adidas Scarpe
Le Wackerly on 19 April 2012 at 4:20 am
woo, do not experienced those great website for some time tzhpk free games Le Wackerly http://kundrav3794.soup.io Le Wackerly
korean plastic surgery statistics on 5 September 2012 at 3:04 am
Almost all of what you assert is supprisingly accurate and it makes me wonder the reason why I had not looked at this with this light before. This piece really did switch the light on for me as far as this particular issue goes. Nevertheless there is one issue I am not really too comfy with and while I try to reconcile that with the actual main theme of the position, allow me see exactly what the rest of your subscribers have to point out.Well done.
Leonardo Sheff on 23 September 2012 at 10:00 pm
Thanks for your thoughts. One thing we’ve noticed is always that banks and also financial institutions have in mind the spending routines of consumers and understand that most of the people max out and about their credit cards around the holiday seasons. They properly take advantage of this specific fact and commence flooding your current inbox in addition to snail-mail box together with hundreds of 0 APR card offers shortly after the holiday season comes to an end. Knowing that should you be like 98% of all American open public, you’ll rush at the opportunity to consolidate credit card debt and switch balances to 0 APR credit cards.
my link on 24 October 2012 at 8:33 am
I usually do not leave a response, but after looking at through a ton of responses here Nat Friedman – Ten Tweetable Scripts. I do have a couple of questions for you if you tend not to mind. Could it be simply me or does it appear like some of the comments look as if they are left by brain dead folks?
And, if you are posting at other sites, I’d like to follow you. Would you post a list of the complete urls of your public pages like your linkedin profile, Facebook page or twitter feed?
krankenkasse stellenangebote on 31 January 2013 at 1:46 am
You should take part in a contest for among the very best blogs on the internet. I will recommend this internet site!
Mozelle on 11 May 2013 at 3:46 am
Hi, this weekend is good in support of me, as this occasion
i am reading this fantastic educational post here at my
house.